From 4b8d344bcd8289d226ce9c5d6d573e0716d291a6 Mon Sep 17 00:00:00 2001 From: "wagic.jeck" Date: Sat, 19 Sep 2009 01:48:42 +0000 Subject: [PATCH] Jeck - Card ID collisions, cache fixes, cache deleted pooling. * mtgid now defaults to 0. * TextScroller will not update when empty. * Cache now moves WCachedResources we're finished with to a garbage pool for later use (to reduce memory fragmentation). * Demo still crashes... but I'm thinking that has to do with fragmentation, not a leak? --- projects/mtg/bin/Res/sets/MOR/_cards.dat | 552 +++++++++--------- projects/mtg/bin/Res/sets/PLC/_cards.dat | 682 +++++++++++------------ projects/mtg/include/GameStateMenu.h | 1 + projects/mtg/include/WCachedResource.h | 10 +- projects/mtg/include/WResourceManager.h | 11 +- projects/mtg/src/GameStateMenu.cpp | 11 +- projects/mtg/src/MTGCard.cpp | 1 + projects/mtg/src/MTGDeck.cpp | 2 +- projects/mtg/src/TextScroller.cpp | 134 ++--- projects/mtg/src/WCachedResource.cpp | 48 +- projects/mtg/src/WResourceManager.cpp | 179 ++++-- 11 files changed, 893 insertions(+), 738 deletions(-) diff --git a/projects/mtg/bin/Res/sets/MOR/_cards.dat b/projects/mtg/bin/Res/sets/MOR/_cards.dat index ce1b8d2be..998b59393 100644 --- a/projects/mtg/bin/Res/sets/MOR/_cards.dat +++ b/projects/mtg/bin/Res/sets/MOR/_cards.dat @@ -1,276 +1,278 @@ -[card] -text=When Ambassador Oak comes enters the battlefield, put a 1/1 green Elf Warrior creature token onto the battlefield. -id=152998 -name=Ambassador Oak -auto=token(Elf Warrior,creature elf,1/1,green) -rarity=C -mana={3}{G} -type=Creature -subtype=Treefolk Warrior -power=3 -toughness=3 -[/card] -[card] -text=At the beginning of your upkeep, you lose 1 life and put a 1/1 black Faerie Rogue creature token with flying into play. -auto=@each my upkeep:life-1 controller -auto=@each my upkeep:token(Faerie,creature faerie,1/1,flying black) -id=152648 -name=Bitterblossom -rarity=R -mana={1}{B} -type=Enchantment -subtype=Faerie -[/card] -[card] -text={T}, Pay 1 life: Add {G} to your mana pool. -id=152705 -auto={T}:Add {G} && life:-1 controller -name=Blightsoil Druid -rarity=C -mana={1}{B} -type=Creature -subtype=Elf Druid -power=1 -toughness=2 -[/card] -[card] -text=Trample Borderland Behemoth gets +4/+4 for each other Giant you control. -id=153102 -name=Borderland Behemoth -auto=foreach(giant|myBattlefield):4/4 other -rarity=R -mana={5}{R}{R} -type=Creature -subtype=Giant Warrior -power=4 -toughness=4 -abilities=trample -[/card] -[card] -text=Enchant creature {1}{W}: Put a +1/+1 counter on enchanted creature. -id=152838 -name=Daily Regimen -target=creature -auto={1}{W}:counter(1/1) -rarity=U -mana={W} -type=Enchantment -subtype=Aura -[/card] -[card] -text=Return target nonland permanent to its owner's hand. -id=152727 -name=Disperse -target=creature,artifact,enchantment -auto=moveTo(ownerHand) -rarity=C -mana={1}{U} -type=Instant -[/card] -[card] -text= -id=153003 -name=Elvish Warrior -rarity=C -mana={G}{G} -type=Creature -subtype=Elf Warrior -power=2 -toughness=3 -[/card] -[card] -text=Flying {U}: Put Fencer Clique on top of its owner's library. -id=157424 -name=Fencer Clique -rarity=C -mana={2}{U}{U} -auto={U}:moveTo(ownerlibrary) -type=Creature -subtype=Faerie Soldier -power=3 -toughness=2 -abilities=flying -[/card] -[card] -text=Festercreep comes into play with a +1/+1 counter on it. {1}{B}, Remove a +1/+1 counter from Festercreep: All other creatures get -1/-1 until end of turn. -id=152944 -name=Festercreep -rarity=C -mana={1}{B} -auto=counter(1/1) -auto={1}{B}:counter(1/1,-1) && lord(creature) -1/-1 -type=Creature -subtype=Elemental -power=0 -toughness=0 -[/card] -[card] -text=Search your library for an enchantment card, reveal it, and put it into your hand. Then shuffle your library. -id=152938 -name=Idyllic Tutor -rarity=R -mana={2}{W} -auto=moveTo(myhand) target(enchantment|myLibrary) -type=Sorcery -[/card] -[card] -text= -id=152967 -name=Indomitable Ancients -rarity=R -mana={2}{W}{W} -type=Creature -subtype=Treefolk Warrior -power=2 -toughness=10 -[/card] -[card] -text=Target creature gets +1/+0 and gains first strike until end of turn. -id=152563 -name=Kindled Fury -target=creature -auto=1/0 -auto=first strike -rarity=C -mana={R} -type=Instant -[/card] -[card] -name=Inspired Sprite -mana={U}{3} -type=Creature -subtype=Faerie Wizard -text=Flash. Flying. Whenever you cast a Wizard spell, you may untap Inspired Sprite. {T}: Draw a card, then discard a card. -abilities=flash,flying -auto=@movedTo(wizard|mystack):may untap -auto={T}:draw:1 && moveto(graveyard) target(*|myhand) -power=2 -toughness=2 -rarity=U -[/card] -[card] -text=Knight creatures you control have double strike. -id=153279 -auto=lord(creature|mybattlefield) double strike -name=Kinsbaile Cavalier -rarity=R -mana={3}{W} -type=Creature -subtype=Kithkin Knight -power=2 -toughness=2 -[/card] -[card] -text=Target player discards X cards at random. -id=157422 -name=Mind Shatter -alias=1167 -rarity=R -mana={X}{B}{B} -type=Sorcery -[/card] -[card] -text=Draw X cards. -id=152628 -name=Mind Spring -alias=1192 -rarity=R -mana={X}{U}{U} -type=Sorcery -[/card] -[card] -text=Counter target noncreature spell. -id=152570 -target=*(-creature)|stack -auto=fizzle -name=Negate -rarity=C -mana={1}{U} -type=Instant -[/card] -[card] -text=Fear -id=152718 -name=Prickly Boggart -rarity=C -mana={B} -type=Creature -subtype=Goblin Rogue -power=1 -toughness=1 -abilities=fear -[/card] -[card] -text=Sacrifice an Elemental: Seething Pathblazer gets +2/+0 and gains first strike until end of turn. -id=153101 -name=Seething Pathblazer -auto={S(elemental|myBattlefield)}:2/0 && first strike -rarity=C -mana={2}{R} -type=Creature -subtype=Elemental Warrior -power=2 -toughness=2 -[/card] -[card] -Name=Shinewend -Mana={1}{W} -Type=Creature -subtype=Elemental -Text=Flying. Shinewend enters the battlefield with a +1/+1 counter on it. {1}{W}, Remove a +1/+1 counter from Shinewend: Destroy target enchantment. -auto=counter(1/1,1) -auto={1}{W}:counter(1/1,-1) && destroy target(enchantment) -abilities=flying -Power=0 -toughness=0 -Rarity=C -[/card] -[card] -Name=Stingmoggie -Mana={3}{R} -Type=Creature -subtype=Elemental -Text=Stingmoggie enters the battlefield with two +1/+1 counters on it. {3}{R}, Remove a +1/+1 counter from Stingmoggie: Destroy target artifact or land. -auto=counter(1/1,2) -auto={1}{W}:counter(1/1,-1) && destroy target(artifact,land) -Power=0 -toughness=0 -Rarity=C -[/card] -[card] -text=Vengeful Firebrand has haste as long as a Warrior card is in your graveyard. R: Vengeful Firebrand gets +1/+0 until end of turn. -id=153153 -name=Vengeful Firebrand -auto=aslongas(warrior|mygraveyard) haste -auto={R}:1/0 -rarity=R -mana={3}{R} -type=Creature -subtype=Elemental Warrior -power=5 -toughness=2 -[/card] -[card] -text=Destroy target nonblack creature. Put a 1/1 black Faerie Rogue creature token with flying into play. -id=157426 -target=creature[-black] -auto=destroy -auto=token(Faerie Rogue,Creature Faerie,1/1,flying black) -name=Violet Pall -rarity=C -mana={4}{B} -type=Tribal Instant -subtype=Faerie -[/card] -[card] -text={3}{B}, Sacrifice a Goblin: Put two 1/1 black Goblin Rogue creature tokens onto the battlefield. -id=153011 -auto={3}{B}{S(goblin|myBattlefield)}:token(Goblin Rogue,Creature Goblin,1/1,black) && token(Goblin Rogue,Creature Goblin,1/1,black) -name=Weirding Shaman -rarity=R -mana={1}{B} -type=Creature -subtype=Goblin Shaman -power=2 -toughness=1 +[card] +text=When Ambassador Oak comes enters the battlefield, put a 1/1 green Elf Warrior creature token onto the battlefield. +id=152998 +name=Ambassador Oak +auto=token(Elf Warrior,creature elf,1/1,green) +rarity=C +mana={3}{G} +type=Creature +subtype=Treefolk Warrior +power=3 +toughness=3 +[/card] +[card] +text=At the beginning of your upkeep, you lose 1 life and put a 1/1 black Faerie Rogue creature token with flying into play. +auto=@each my upkeep:life-1 controller +auto=@each my upkeep:token(Faerie,creature faerie,1/1,flying black) +id=152648 +name=Bitterblossom +rarity=R +mana={1}{B} +type=Enchantment +subtype=Faerie +[/card] +[card] +text={T}, Pay 1 life: Add {G} to your mana pool. +id=152705 +auto={T}:Add {G} && life:-1 controller +name=Blightsoil Druid +rarity=C +mana={1}{B} +type=Creature +subtype=Elf Druid +power=1 +toughness=2 +[/card] +[card] +text=Trample Borderland Behemoth gets +4/+4 for each other Giant you control. +id=153102 +name=Borderland Behemoth +auto=foreach(giant|myBattlefield):4/4 other +rarity=R +mana={5}{R}{R} +type=Creature +subtype=Giant Warrior +power=4 +toughness=4 +abilities=trample +[/card] +[card] +text=Enchant creature {1}{W}: Put a +1/+1 counter on enchanted creature. +id=152838 +name=Daily Regimen +target=creature +auto={1}{W}:counter(1/1) +rarity=U +mana={W} +type=Enchantment +subtype=Aura +[/card] +[card] +text=Return target nonland permanent to its owner's hand. +id=152727 +name=Disperse +target=creature,artifact,enchantment +auto=moveTo(ownerHand) +rarity=C +mana={1}{U} +type=Instant +[/card] +[card] +text= +id=153003 +name=Elvish Warrior +rarity=C +mana={G}{G} +type=Creature +subtype=Elf Warrior +power=2 +toughness=3 +[/card] +[card] +text=Flying {U}: Put Fencer Clique on top of its owner's library. +id=157424 +name=Fencer Clique +rarity=C +mana={2}{U}{U} +auto={U}:moveTo(ownerlibrary) +type=Creature +subtype=Faerie Soldier +power=3 +toughness=2 +abilities=flying +[/card] +[card] +text=Festercreep comes into play with a +1/+1 counter on it. {1}{B}, Remove a +1/+1 counter from Festercreep: All other creatures get -1/-1 until end of turn. +id=152944 +name=Festercreep +rarity=C +mana={1}{B} +auto=counter(1/1) +auto={1}{B}:counter(1/1,-1) && lord(creature) -1/-1 +type=Creature +subtype=Elemental +power=0 +toughness=0 +[/card] +[card] +text=Search your library for an enchantment card, reveal it, and put it into your hand. Then shuffle your library. +id=152938 +name=Idyllic Tutor +rarity=R +mana={2}{W} +auto=moveTo(myhand) target(enchantment|myLibrary) +type=Sorcery +[/card] +[card] +text= +id=152967 +name=Indomitable Ancients +rarity=R +mana={2}{W}{W} +type=Creature +subtype=Treefolk Warrior +power=2 +toughness=10 +[/card] +[card] +text=Target creature gets +1/+0 and gains first strike until end of turn. +id=152563 +name=Kindled Fury +target=creature +auto=1/0 +auto=first strike +rarity=C +mana={R} +type=Instant +[/card] +[card] +name=Inspired Sprite +mana={U}{3} +type=Creature +subtype=Faerie Wizard +text=Flash. Flying. Whenever you cast a Wizard spell, you may untap Inspired Sprite. {T}: Draw a card, then discard a card. +abilities=flash,flying +auto=@movedTo(wizard|mystack):may untap +auto={T}:draw:1 && moveto(graveyard) target(*|myhand) +power=2 +toughness=2 +rarity=U +[/card] +[card] +text=Knight creatures you control have double strike. +id=153279 +auto=lord(creature|mybattlefield) double strike +name=Kinsbaile Cavalier +rarity=R +mana={3}{W} +type=Creature +subtype=Kithkin Knight +power=2 +toughness=2 +[/card] +[card] +text=Target player discards X cards at random. +id=157422 +name=Mind Shatter +alias=1167 +rarity=R +mana={X}{B}{B} +type=Sorcery +[/card] +[card] +text=Draw X cards. +id=152628 +name=Mind Spring +alias=1192 +rarity=R +mana={X}{U}{U} +type=Sorcery +[/card] +[card] +text=Counter target noncreature spell. +id=152570 +target=*(-creature)|stack +auto=fizzle +name=Negate +rarity=C +mana={1}{U} +type=Instant +[/card] +[card] +text=Fear +id=152718 +name=Prickly Boggart +rarity=C +mana={B} +type=Creature +subtype=Goblin Rogue +power=1 +toughness=1 +abilities=fear +[/card] +[card] +text=Sacrifice an Elemental: Seething Pathblazer gets +2/+0 and gains first strike until end of turn. +id=153101 +name=Seething Pathblazer +auto={S(elemental|myBattlefield)}:2/0 && first strike +rarity=C +mana={2}{R} +type=Creature +subtype=Elemental Warrior +power=2 +toughness=2 +[/card] +[card] +id=152659 +Name=Shinewend +Mana={1}{W} +Type=Creature +subtype=Elemental +Text=Flying. Shinewend enters the battlefield with a +1/+1 counter on it. {1}{W}, Remove a +1/+1 counter from Shinewend: Destroy target enchantment. +auto=counter(1/1,1) +auto={1}{W}:counter(1/1,-1) && destroy target(enchantment) +abilities=flying +Power=0 +toughness=0 +Rarity=C +[/card] +[card] +id=152704 +Name=Stingmoggie +Mana={3}{R} +Type=Creature +subtype=Elemental +Text=Stingmoggie enters the battlefield with two +1/+1 counters on it. {3}{R}, Remove a +1/+1 counter from Stingmoggie: Destroy target artifact or land. +auto=counter(1/1,2) +auto={1}{W}:counter(1/1,-1) && destroy target(artifact,land) +Power=0 +toughness=0 +Rarity=C +[/card] +[card] +text=Vengeful Firebrand has haste as long as a Warrior card is in your graveyard. R: Vengeful Firebrand gets +1/+0 until end of turn. +id=153153 +name=Vengeful Firebrand +auto=aslongas(warrior|mygraveyard) haste +auto={R}:1/0 +rarity=R +mana={3}{R} +type=Creature +subtype=Elemental Warrior +power=5 +toughness=2 +[/card] +[card] +text=Destroy target nonblack creature. Put a 1/1 black Faerie Rogue creature token with flying into play. +id=157426 +target=creature[-black] +auto=destroy +auto=token(Faerie Rogue,Creature Faerie,1/1,flying black) +name=Violet Pall +rarity=C +mana={4}{B} +type=Tribal Instant +subtype=Faerie +[/card] +[card] +text={3}{B}, Sacrifice a Goblin: Put two 1/1 black Goblin Rogue creature tokens onto the battlefield. +id=153011 +auto={3}{B}{S(goblin|myBattlefield)}:token(Goblin Rogue,Creature Goblin,1/1,black) && token(Goblin Rogue,Creature Goblin,1/1,black) +name=Weirding Shaman +rarity=R +mana={1}{B} +type=Creature +subtype=Goblin Shaman +power=2 +toughness=1 [/card] \ No newline at end of file diff --git a/projects/mtg/bin/Res/sets/PLC/_cards.dat b/projects/mtg/bin/Res/sets/PLC/_cards.dat index fb2ae0854..ba709da9d 100644 --- a/projects/mtg/bin/Res/sets/PLC/_cards.dat +++ b/projects/mtg/bin/Res/sets/PLC/_cards.dat @@ -1,342 +1,342 @@ -[card] -text=First strike, protection from white -id=130715 -name=Blood Knight -rarity=U -type=Creature -subtype=human knight -mana={R}{R} -power=2 -toughness=2 -abilities=first strike,protection from white -color=Red -[/card] -[card] -text=Target creature gets +3/+3 until end of turn. -target=creature -auto=3/3 -id=122373 -name=Brute Force -rarity=C -color=Red -type=Instant -mana={R} -[/card] -[card] -text=Other white creatures get +1/+1. Nonwhite creatures get -1/-1. Pay 2 life: Return Crovax, Ascendant Hero to its owner's hand. -abilities=legendary -auto=lord(creature[white]) 1/1 -auto=loard(creature[-white] -1/-1 -auto={0}life:-2:moveTo(ownerhand) -id=122487 -name=Crovax, Ascendant Hero -rarity=R -color=White -type=Creature -mana={4}{W}{W} -power=4 -subtype=Human Lord -toughness=4 -[/card] -[card] -text=Destroy all creatures. They can't be regenerated. -auto=bury all(creature) -id=122423 -name=Damnation -rarity=R -type=Sorcery -mana={2}{B}{B} -color=Black -[/card] -[card] -text=Creatures you control get +1/+1. -auto=lord(creature|myinplay) 1/1 -id=122367 -name=Gaea's Anthem -rarity=R -type=Enchantment -mana={1}{G}{G} -color=Green -[/card] -[card] -text=Trample, haste At end of turn, sacrifice Groundbreaker. -abilities=trample,haste -auto=@next endofturn:bury -id=122429 -name=Groundbreaker -rarity=R -color=Green -type=Creature -mana={G}{G}{G} -power=6 -subtype=Elemental -toughness=1 -[/card] -[card] -text=Draw three cards. -auto=draw:3 -id=122362 -name=Harmonize -rarity=U -color=Green -type=Sorcery -mana={2}{G}{G} -[/card] -[card] -text=Hedge Troll gets +1/+1 as long as you control a Plains. {W}: Regenerate Hedge Troll. -auto=aslongas(plains|myinplay) 1/1 -auto={W}:regenerate -id=122405 -name=Hedge Troll -rarity=U -color=Green -type=Creature -mana={2}{G} -power=2 -subtype=Troll Cleric -toughness=2 -[/card] -[card] -text=Flying {W}{W}{W}: Regenerate Malach of the Dawn. -abilities=flying -auto={W}{W}{W}:regenerate -id=122481 -name=Malach of the Dawn -rarity=U -color=White -type=Creature -mana={2}{W}{W} -power=2 -subtype=Angel -toughness=4 -[/card] -[card] -text=Sunlance deals 3 damage to target nonwhite creature. -target=creature[-white] -auto=Damage:3 -id=122355 -name=Sunlance -rarity=C -color=White -type=Sorcery -mana={w} -[/card] -[card] -text=Flying, Vigilance -id=125873 -name=Serra Sphinx -rarity=R -type=Creature -subtype=Sphinx -mana={3}{U}{U} -power=4 -toughness=4 -abilities=vigilance,flying -color=Blue -[/card] -[card] -text=Swampwalk {G}: Regenerate Mire Boa. -id=122420 -name=Mire Boa -rarity=C -type=Creature -subtype=Snake -mana={1}{G} -power=2 -toughness=1 -auto={G}:regenerate -abilities=swampwalk -color=Green -[/card] -[card] -text=Reach -id=122268 -name=Needlepeak Spider -rarity=C -type=Creature -subtype=Spider -mana={3}{R} -power=4 -toughness=2 -abilities=reach -color=Red -[/card] -[card] -text={T}:Prodigal Pyromancer deals 1 damage to target creature or player. -id=134752 -name=Prodigal Pyromancer -rarity=C -type=Creature -subtype=Human Wizard -mana={2}{R} -power=1 -toughness=1 -auto={T}:damage:1 target(creature,player) -color=Red -[/card] -#[card] -#text=At end of turn, if no creatures are in play, sacrifice Pyrohemia. {R}: Pyrohemia #deals 1 damage to each creature and each player. -#alias=1172 -#id=122436 -#name=Pyrohemia -#rarity=U -#type=Enchantment -#mana={2}{R}{R} -#color=Red -#[/card] -[card] -text={B}, {T}:Tap target creature. -id=130718 -name=Rathi Trapper -rarity=C -type=Creature -subtype=Human Rebel Rogue -mana={1}{B} -power=1 -toughness=2 -auto={B}{T}:tap target(creature) -color=Black -[/card] -[card] -text={W}:Regenerate Revered Dead. -id=122282 -name=Revered Dead -rarity=C -type=Creature -subtype=Spirit Soldier -mana={1}{W} -power=1 -toughness=1 -auto={W}:regenerate -color=White -[/card] -[card] -text=Destroy target nonwhite permanent. -target=*[-white] -auto=destroy -id=122435 -name=Saltblast -rarity=U -color=White -type=Sorcery -mana={3}{W}{W} -[/card] -[card] -text={T}:Target creature gets -2/-0 until end of turn. -id=124037 -name=Saltfield Recluse -rarity=C -type=Creature -subtype=Human Rebel Cleric -mana={2}{W} -power=1 -toughness=2 -auto={T}:-2/-0 target(creature) -color=White -[/card] -[card] -text=Sacrifice Seal of Primordium: Destroy target artifact or enchantment. -auto={S}:destroy target(artifact,enchantment) -id=130816 -name=Seal of Primordium -rarity=C -type=Enchantment -mana={1}{G} -color=Green -[/card] -[card] -text=Enchant creature Enchanted creature can't attack or block. Enchanted creature has "{T}:Add one mana of any color to your mana pool." -auto=cantattack,cantblock -auto={T}:add:{W} -auto={T}:add:{U} -auto={T}:add:{B} -auto={T}:add:{R} -auto={T}:add:{G} -id=131004 -name=Utopia Vow -rarity=C -type=Enchantment -mana={1}{G} -color=Green -subtype=Aura -[/card] -[card] -text=Enchant creature Enchanted creature has lifelink. -auto=lifelink -id=122366 -name=Vampiric link -rarity=U -type=Enchantment -mana={B} -color=Black -subtype=Aura -[/card] -[card] -text=All Sliver creatures have trample. -id=126015 -name=Battering Sliver -rarity=C -type=Creature -subtype=Sliver -mana={5}{R} -power=4 -toughness=4 -auto=lord(Sliver) trample -abilities=trample -color=Red -[/card] -[card] -text=All Sliver creatures have haste. -id=126018 -name=Reflex Sliver -rarity=C -type=Creature -subtype=Sliver -mana={3}{G} -power=2 -toughness=2 -auto=lord(Sliver) haste -abilities=haste -color=Green -[/card] -[card] -text=All Sliver creatures get +1/+1. -id=125879 -name=Sinew Sliver -rarity=C -type=Creature -subtype=Sliver -mana={1}{W} -power=2 -toughness=2 -auto=lord(Sliver) 1/1 -color=White -[/card] -[card] -text=All Sliver creatures have first strike. -id=126022 -name=Spitting Sliver -rarity=C -type=Creature -subtype=Sliver -mana={4}{B} -power=3 -toughness=3 -auto=lord(Sliver) first strike -abilities=first strike -color=Black -[/card] -[card] -text=All Sliver creatures have vigilance. -id=124044 -name=Synchronous Sliver -rarity=C -type=Creature -subtype=Sliver -mana={4}{U} -power=3 -toughness=3 -auto=lord(Sliver) vigilance -abilities=vigilance -color=Blue +[card] +text=First strike, protection from white +id=130715 +name=Blood Knight +rarity=U +type=Creature +subtype=human knight +mana={R}{R} +power=2 +toughness=2 +abilities=first strike,protection from white +color=Red +[/card] +[card] +text=Target creature gets +3/+3 until end of turn. +target=creature +auto=3/3 +id=122373 +name=Brute Force +rarity=C +color=Red +type=Instant +mana={R} +[/card] +[card] +text=Other white creatures get +1/+1. Nonwhite creatures get -1/-1. Pay 2 life: Return Crovax, Ascendant Hero to its owner's hand. +abilities=legendary +auto=lord(creature[white]) 1/1 +auto=loard(creature[-white] -1/-1 +auto={0}life:-2:moveTo(ownerhand) +id=122487 +name=Crovax, Ascendant Hero +rarity=R +color=White +type=Creature +mana={4}{W}{W} +power=4 +subtype=Human Lord +toughness=4 +[/card] +[card] +text=Destroy all creatures. They can't be regenerated. +auto=bury all(creature) +id=122423 +name=Damnation +rarity=R +type=Sorcery +mana={2}{B}{B} +color=Black +[/card] +[card] +text=Creatures you control get +1/+1. +auto=lord(creature|myinplay) 1/1 +id=122367 +name=Gaea's Anthem +rarity=R +type=Enchantment +mana={1}{G}{G} +color=Green +[/card] +[card] +text=Trample, haste At end of turn, sacrifice Groundbreaker. +abilities=trample,haste +auto=@next endofturn:bury +id=122429 +name=Groundbreaker +rarity=R +color=Green +type=Creature +mana={G}{G}{G} +power=6 +subtype=Elemental +toughness=1 +[/card] +[card] +text=Draw three cards. +auto=draw:3 +id=122362 +name=Harmonize +rarity=U +color=Green +type=Sorcery +mana={2}{G}{G} +[/card] +[card] +text=Hedge Troll gets +1/+1 as long as you control a Plains. {W}: Regenerate Hedge Troll. +auto=aslongas(plains|myinplay) 1/1 +auto={W}:regenerate +id=122405 +name=Hedge Troll +rarity=U +color=Green +type=Creature +mana={2}{G} +power=2 +subtype=Troll Cleric +toughness=2 +[/card] +[card] +text=Flying {W}{W}{W}: Regenerate Malach of the Dawn. +abilities=flying +auto={W}{W}{W}:regenerate +id=122481 +name=Malach of the Dawn +rarity=U +color=White +type=Creature +mana={2}{W}{W} +power=2 +subtype=Angel +toughness=4 +[/card] +[card] +text=Sunlance deals 3 damage to target nonwhite creature. +target=creature[-white] +auto=Damage:3 +id=122355 +name=Sunlance +rarity=C +color=White +type=Sorcery +mana={w} +[/card] +[card] +text=Flying, Vigilance +id=125873 +name=Serra Sphinx +rarity=R +type=Creature +subtype=Sphinx +mana={3}{U}{U} +power=4 +toughness=4 +abilities=vigilance,flying +color=Blue +[/card] +[card] +text=Swampwalk {G}: Regenerate Mire Boa. +id=122420 +name=Mire Boa +rarity=C +type=Creature +subtype=Snake +mana={1}{G} +power=2 +toughness=1 +auto={G}:regenerate +abilities=swampwalk +color=Green +[/card] +[card] +text=Reach +id=122268 +name=Needlepeak Spider +rarity=C +type=Creature +subtype=Spider +mana={3}{R} +power=4 +toughness=2 +abilities=reach +color=Red +[/card] +[card] +text={T}:Prodigal Pyromancer deals 1 damage to target creature or player. +id=122338 +name=Prodigal Pyromancer +rarity=C +type=Creature +subtype=Human Wizard +mana={2}{R} +power=1 +toughness=1 +auto={T}:damage:1 target(creature,player) +color=Red +[/card] +#[card] +#text=At end of turn, if no creatures are in play, sacrifice Pyrohemia. {R}: Pyrohemia #deals 1 damage to each creature and each player. +#alias=1172 +#id=122436 +#name=Pyrohemia +#rarity=U +#type=Enchantment +#mana={2}{R}{R} +#color=Red +#[/card] +[card] +text={B}, {T}:Tap target creature. +id=130718 +name=Rathi Trapper +rarity=C +type=Creature +subtype=Human Rebel Rogue +mana={1}{B} +power=1 +toughness=2 +auto={B}{T}:tap target(creature) +color=Black +[/card] +[card] +text={W}:Regenerate Revered Dead. +id=122282 +name=Revered Dead +rarity=C +type=Creature +subtype=Spirit Soldier +mana={1}{W} +power=1 +toughness=1 +auto={W}:regenerate +color=White +[/card] +[card] +text=Destroy target nonwhite permanent. +target=*[-white] +auto=destroy +id=122435 +name=Saltblast +rarity=U +color=White +type=Sorcery +mana={3}{W}{W} +[/card] +[card] +text={T}:Target creature gets -2/-0 until end of turn. +id=124037 +name=Saltfield Recluse +rarity=C +type=Creature +subtype=Human Rebel Cleric +mana={2}{W} +power=1 +toughness=2 +auto={T}:-2/-0 target(creature) +color=White +[/card] +[card] +text=Sacrifice Seal of Primordium: Destroy target artifact or enchantment. +auto={S}:destroy target(artifact,enchantment) +id=130816 +name=Seal of Primordium +rarity=C +type=Enchantment +mana={1}{G} +color=Green +[/card] +[card] +text=Enchant creature Enchanted creature can't attack or block. Enchanted creature has "{T}:Add one mana of any color to your mana pool." +auto=cantattack,cantblock +auto={T}:add:{W} +auto={T}:add:{U} +auto={T}:add:{B} +auto={T}:add:{R} +auto={T}:add:{G} +id=131004 +name=Utopia Vow +rarity=C +type=Enchantment +mana={1}{G} +color=Green +subtype=Aura +[/card] +[card] +text=Enchant creature Enchanted creature has lifelink. +auto=lifelink +id=122366 +name=Vampiric link +rarity=U +type=Enchantment +mana={B} +color=Black +subtype=Aura +[/card] +[card] +text=All Sliver creatures have trample. +id=126015 +name=Battering Sliver +rarity=C +type=Creature +subtype=Sliver +mana={5}{R} +power=4 +toughness=4 +auto=lord(Sliver) trample +abilities=trample +color=Red +[/card] +[card] +text=All Sliver creatures have haste. +id=126018 +name=Reflex Sliver +rarity=C +type=Creature +subtype=Sliver +mana={3}{G} +power=2 +toughness=2 +auto=lord(Sliver) haste +abilities=haste +color=Green +[/card] +[card] +text=All Sliver creatures get +1/+1. +id=125879 +name=Sinew Sliver +rarity=C +type=Creature +subtype=Sliver +mana={1}{W} +power=2 +toughness=2 +auto=lord(Sliver) 1/1 +color=White +[/card] +[card] +text=All Sliver creatures have first strike. +id=126022 +name=Spitting Sliver +rarity=C +type=Creature +subtype=Sliver +mana={4}{B} +power=3 +toughness=3 +auto=lord(Sliver) first strike +abilities=first strike +color=Black +[/card] +[card] +text=All Sliver creatures have vigilance. +id=124044 +name=Synchronous Sliver +rarity=C +type=Creature +subtype=Sliver +mana={4}{U} +power=3 +toughness=3 +auto=lord(Sliver) vigilance +abilities=vigilance +color=Blue [/card] \ No newline at end of file diff --git a/projects/mtg/include/GameStateMenu.h b/projects/mtg/include/GameStateMenu.h index d1616e478..9e37b06e4 100644 --- a/projects/mtg/include/GameStateMenu.h +++ b/projects/mtg/include/GameStateMenu.h @@ -20,6 +20,7 @@ class GameStateMenu: public GameState, public JGuiListener JTexture * bgTexture; JTexture * movingWTexture; JQuad * mBg; + JQuad * mSplash; JQuad * mMovingW; float mCreditsYPos; int currentState; diff --git a/projects/mtg/include/WCachedResource.h b/projects/mtg/include/WCachedResource.h index df15d522a..0659c1e2b 100644 --- a/projects/mtg/include/WCachedResource.h +++ b/projects/mtg/include/WCachedResource.h @@ -15,7 +15,8 @@ public: WResource(); virtual ~WResource(); - + + virtual void Trash()=0; //Delete the cacheActual. virtual void Nullify()=0; //For when our size is 0, so we don't free anything by mistake. virtual unsigned long size()=0; //Size of cached item in bytes. virtual bool isGood()=0; //Return true if this has data. @@ -38,6 +39,8 @@ public: friend class WResourceManager; template friend class WCache; + virtual ~WCachedResource() {}; + virtual void Refresh(string filename)=0; //Basically calls Attempt(filename) and remaps in situ. virtual bool Attempt(string filename, int submode, int & error)=0; //Returns true if we've loaded our data and isGood(). }; @@ -48,6 +51,7 @@ public: WTrackedQuad(string _resname); ~WTrackedQuad(); void Nullify(); + void Trash(); unsigned long size(); bool isGood(); @@ -73,6 +77,7 @@ public: bool compare(JTexture * t) {return (t == texture);}; void Nullify(); + void Trash(); JTexture * Actual(); //Return this texture as is. Does not make a new one. JQuad * GetQuad(string resname); @@ -86,6 +91,7 @@ protected: JTexture * texture; bool bVRAM; vector trackedQuads; + static vector garbageTQs; }; class WCachedParticles: public WCachedResource{ @@ -96,6 +102,7 @@ public: ~WCachedParticles(); void Nullify(); + void Trash(); void Refresh(string filename); unsigned long size(); bool isGood(); @@ -114,6 +121,7 @@ public: WCachedSample(); ~WCachedSample(); void Nullify(); + void Trash(); bool compare(JSample * s) {return (s == sample);}; unsigned long size(); bool isGood(); diff --git a/projects/mtg/include/WResourceManager.h b/projects/mtg/include/WResourceManager.h index d13312ebe..26220f027 100644 --- a/projects/mtg/include/WResourceManager.h +++ b/projects/mtg/include/WResourceManager.h @@ -19,10 +19,11 @@ //Hard Limits. -#define MAX_CACHE_OBJECTS 400 +#define MAX_CACHE_OBJECTS HUGE_CACHE_ITEMS #define MAX_CACHE_ATTEMPTS 10 #define MAX_CACHE_MISSES 200 #define MAX_CACHED_SAMPLES 0 +#define MAX_CACHE_GARBAGE 10 enum ENUM_WRES_INFO{ WRES_UNLOCKED = 0, //Resource is unlocked. @@ -61,7 +62,8 @@ enum ENUM_CACHE_ERROR{ CACHE_ERROR_NONE = 0, CACHE_ERROR_NOT_CACHED = CACHE_ERROR_NONE, CACHE_ERROR_404, - CACHE_ERROR_BAD, + CACHE_ERROR_BAD, //Something went wrong with item->attempt() + CACHE_ERROR_BAD_ALLOC, //Couldn't allocate item CACHE_ERROR_LOST, CACHE_ERROR_NOT_MANAGED, }; @@ -89,15 +91,17 @@ public: protected: bool RemoveItem(cacheItem * item, bool force = true); //Removes an item, deleting it. if(force), ignores locks / permanent bool UnlinkCache(cacheItem * item); //Removes an item from our cache, does not delete it. Use with care. - bool Delete(cacheItem * item); //Call SAFE_DELETE on cacheItem. If maxCached == 0, nullify first. (This means you have to free that cacheActual later!) + bool Delete(cacheItem * item); //SAFE_DELETE and garbage collect. If maxCached == 0, nullify first. (This means you have to free that cacheActual later!) cacheItem* Get(string id, int style = RETRIEVE_NORMAL, int submode = CACHE_NORMAL); //Subordinate to Retrieve. cacheItem* AttemptNew(string filename, int submode); //Attempts a new cache item, progressively clearing cache if it fails. + cacheItem* Recycle(); //Returns a cache item from the trash. string makeID(string filename, int submode); //Makes an ID appropriate to the submode. string makeFilename(string id, int submode); //Makes a filename from an ID. map cache; map managed; //Cache can be arbitrarily large, so managed items are seperate. + vector garbage; //Garbage collection. unsigned long totalSize; unsigned long cacheSize; @@ -138,6 +142,7 @@ public: void Release(JQuad * quad); void Release(JSample * sample); + bool RemoveOldest(); bool Cleanup(); //Force a cleanup. Return false if nothing removed. void ClearMisses(); //Remove all cache misses. diff --git a/projects/mtg/src/GameStateMenu.cpp b/projects/mtg/src/GameStateMenu.cpp index ffb494ae8..b9bd92d48 100644 --- a/projects/mtg/src/GameStateMenu.cpp +++ b/projects/mtg/src/GameStateMenu.cpp @@ -64,6 +64,9 @@ GameStateMenu::GameStateMenu(GameApp* parent): GameState(parent) mGuiController = NULL; subMenuController = NULL; gameTypeMenu = NULL; + mSplash = NULL; + mBg = NULL; + mMovingW = NULL; //bgMusic = NULL; timeIndex = 0; angleMultiplier = MIN_ANGLE_MULTIPLIER; @@ -315,6 +318,7 @@ void GameStateMenu::Update(float dt) std::ifstream file(options.profileFile(PLAYER_COLLECTION,"",false).c_str()); if(file){ file.close(); + resources.Release(mSplash); currentState = MENU_STATE_MAJOR_MAINMENU | MENU_STATE_MINOR_NONE; }else{ currentState = MENU_STATE_MAJOR_FIRST_TIME | MENU_STATE_MINOR_NONE; @@ -414,9 +418,10 @@ void GameStateMenu::Render() renderer->ClearScreen(ARGB(0,0,0,0)); JLBFont * mFont = resources.GetJLBFont(Constants::MENU_FONT); if ((currentState & MENU_STATE_MAJOR) == MENU_STATE_MAJOR_LOADING_CARDS){ - JQuad* splashQuad = resources.RetrieveTempQuad("splash.jpg"); - if (splashQuad){ - renderer->RenderQuad(splashQuad,0,0); + if(!mSplash) + mSplash = resources.RetrieveQuad("splash.jpg"); + if (mSplash){ + renderer->RenderQuad(mSplash,0,0); }else{ char text[512]; sprintf(text, _("LOADING SET: %s").c_str(), mCurrentSetName); diff --git a/projects/mtg/src/MTGCard.cpp b/projects/mtg/src/MTGCard.cpp index 4725c9959..aecfe3e31 100644 --- a/projects/mtg/src/MTGCard.cpp +++ b/projects/mtg/src/MTGCard.cpp @@ -69,6 +69,7 @@ int MTGCard::init(){ colors[i] = 0; } setId = 0; + mtgid = 0; magicText = ""; spellTargetType = ""; alias = 0; diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index 00ddb2a62..d18c21ef8 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -279,7 +279,7 @@ int MTGAllCards::readConfLine(std::ifstream &file, int set_id){ char outBuf[4096]; sprintf(outBuf,"warning, card id collision! : %i - %s\n", newId, tempCard->name.c_str()); OutputDebugString (outBuf); - delete tempCard; + SAFE_DELETE(tempCard); }else{ ids.push_back(newId); collection[newId] = tempCard; diff --git a/projects/mtg/src/TextScroller.cpp b/projects/mtg/src/TextScroller.cpp index dc4599049..42b177865 100644 --- a/projects/mtg/src/TextScroller.cpp +++ b/projects/mtg/src/TextScroller.cpp @@ -1,66 +1,68 @@ -#include "../include/TextScroller.h" - -#include - -TextScroller::TextScroller(JLBFont * font, float x, float y, float width, float speed):JGuiObject(0){ - mFont = font; - mWidth = width; - mSpeed = speed; - mX = x; - mY = y; - start = -width; - timer = 0; - currentId = 0; - mRandom = 0; -} - -void TextScroller::setRandom(int mode){ - mRandom = mode; - if (mRandom && strings.size()){ - currentId = (rand() % strings.size()); - mText = strings[currentId]; - } -} - -void TextScroller::Add(string text){ - if (!strings.size()) mText = text; - strings.push_back(text); -} - -void TextScroller::Reset(){ - strings.clear(); -} - -void TextScroller::Update(float dt){ - start+=mSpeed*dt; - if (start > mFont->GetStringWidth(mText.c_str())){ - start = -mWidth; - if (mRandom){ - currentId = (rand() % strings.size()); - }else{ - currentId++; - if (currentId > strings.size()-1)currentId = 0; - } - mText = strings[currentId]; - } - -} - -void TextScroller::Render(){ - mFont->DrawString(mText.c_str(),mX,mY,JGETEXT_LEFT,start,mWidth); -} - -ostream& TextScroller::toString(ostream& out) const -{ - return out << "TextScroller ::: mText : " << mText - << " ; tempText : " << tempText - << " ; mFont : " << mFont - << " ; mWidth : " << mWidth - << " ; mSpeed : " << mSpeed - << " ; mX,mY : " << mX << "," << mY - << " ; start : " << start - << " ; timer : " << timer - << " ; strings : ?" // << strings - << " ; currentId : " << currentId - << " ; mRandom : " << mRandom; -} +#include "../include/TextScroller.h" + +#include + +TextScroller::TextScroller(JLBFont * font, float x, float y, float width, float speed):JGuiObject(0){ + mFont = font; + mWidth = width; + mSpeed = speed; + mX = x; + mY = y; + start = -width; + timer = 0; + currentId = 0; + mRandom = 0; +} + +void TextScroller::setRandom(int mode){ + mRandom = mode; + if (mRandom && strings.size()){ + currentId = (rand() % strings.size()); + mText = strings[currentId]; + } +} + +void TextScroller::Add(string text){ + if (!strings.size()) mText = text; + strings.push_back(text); +} + +void TextScroller::Reset(){ + strings.clear(); +} + +void TextScroller::Update(float dt){ + if(!strings.size()) + return; + start+=mSpeed*dt; + if (start > mFont->GetStringWidth(mText.c_str())){ + start = -mWidth; + if (mRandom){ + currentId = (rand() % strings.size()); + }else{ + currentId++; + if (currentId > strings.size()-1)currentId = 0; + } + mText = strings[currentId]; + } + +} + +void TextScroller::Render(){ + mFont->DrawString(mText.c_str(),mX,mY,JGETEXT_LEFT,start,mWidth); +} + +ostream& TextScroller::toString(ostream& out) const +{ + return out << "TextScroller ::: mText : " << mText + << " ; tempText : " << tempText + << " ; mFont : " << mFont + << " ; mWidth : " << mWidth + << " ; mSpeed : " << mSpeed + << " ; mX,mY : " << mX << "," << mY + << " ; start : " << start + << " ; timer : " << timer + << " ; strings : ?" // << strings + << " ; currentId : " << currentId + << " ; mRandom : " << mRandom; +} diff --git a/projects/mtg/src/WCachedResource.cpp b/projects/mtg/src/WCachedResource.cpp index 8dee30de1..3a89a1dce 100644 --- a/projects/mtg/src/WCachedResource.cpp +++ b/projects/mtg/src/WCachedResource.cpp @@ -59,6 +59,8 @@ void WResource::hit(){ lastTime = resources.nowTime(); } //WCachedTexture +vector WCachedTexture::garbageTQs; + WCachedTexture::WCachedTexture(){ #ifdef DEBUG_CACHE OutputDebugString("Cached texture created.\n"); @@ -122,7 +124,13 @@ bool WCachedTexture::ReleaseQuad(JQuad* quad){ tq->unlock(); if(!tq->isLocked()){ - SAFE_DELETE(tq); + if(WCachedTexture::garbageTQs.size() < MAX_CACHE_GARBAGE){ + tq->Trash(); + garbageTQs.push_back(tq); + } + else + SAFE_DELETE(tq); + trackedQuads.erase(it); } @@ -157,7 +165,14 @@ WTrackedQuad * WCachedTexture::GetTrackedQuad(float offX, float offY, float widt if(tq == NULL){ allocated = true; - tq = NEW WTrackedQuad(resname); + vector::iterator gtq = WCachedTexture::garbageTQs.begin(); + if(gtq != WCachedTexture::garbageTQs.end()) + { + tq = *gtq; + garbageTQs.erase(gtq); + } + else + tq = NEW WTrackedQuad(resname); } if(tq == NULL) @@ -314,6 +329,22 @@ void WCachedTexture::Nullify(){ if(texture) texture = NULL; } +void WCachedTexture::Trash(){ + SAFE_DELETE(texture); + + vector::iterator it; + WTrackedQuad * tq = NULL; + + for(it=trackedQuads.begin();it!=trackedQuads.end();it++){ + tq = (*it); + if(WCachedTexture::garbageTQs.size() > MAX_CACHE_GARBAGE) + SAFE_DELETE(tq); + else{ + WCachedTexture::garbageTQs.push_back(tq); + } + } + trackedQuads.clear(); +} //WCachedSample void WCachedSample::Nullify(){ @@ -322,6 +353,10 @@ void WCachedSample::Nullify(){ } } +void WCachedSample::Trash(){ + SAFE_DELETE(sample); +} + WCachedSample::WCachedSample(){ #ifdef DEBUG_CACHE OutputDebugString("Cached sample created.\n"); @@ -452,11 +487,20 @@ void WCachedParticles::Nullify(){ particles = NULL; } +void WCachedParticles::Trash(){ + SAFE_DELETE(particles); +} + //WTrackedQuad void WTrackedQuad::Nullify() { quad = NULL; } +void WTrackedQuad::Trash(){ + resname.clear(); + SAFE_DELETE(quad); +} + #if defined DEBUG_CACHE int WTrackedQuad::totalTracked = 0; #endif diff --git a/projects/mtg/src/WResourceManager.cpp b/projects/mtg/src/WResourceManager.cpp index 51a0e9e0c..3b892dbb6 100644 --- a/projects/mtg/src/WResourceManager.cpp +++ b/projects/mtg/src/WResourceManager.cpp @@ -10,9 +10,30 @@ #include "../include/WResourceManager.h" WResourceManager resources; - unsigned int vTime = 0; +void handle_new_failure(){ + OutputDebugString("NEW failed. Attempting to clear cache."); +#ifdef DEBUG_CACHE + resources.debugMessage = "Emergency cache cleanup!"; +#endif + if(!resources.RemoveOldest()){ + OutputDebugString("Nothing to clear from cache. Abort."); + abort(); + } +} + +bool WResourceManager::RemoveOldest(){ + if(sampleWCache.RemoveOldest()) + return true; + if(textureWCache.RemoveOldest()) + return true; + if(psiWCache.RemoveOldest()) + return true; + + return false; +} + //WResourceManager void WResourceManager::DebugRender(){ JRenderer* renderer = JRenderer::GetInstance(); @@ -168,18 +189,27 @@ WResourceManager::~WResourceManager(){ SAFE_DELETE(wm); } managedQuads.clear(); + + //Remove all our reserved WTrackedQuads from WCachedTexture + vector::iterator g; + for(g=WCachedTexture::garbageTQs.begin();g!=WCachedTexture::garbageTQs.end();g++){ + WTrackedQuad * tq = *g; + SAFE_DELETE(tq); + } LOG("==Successfully Destroyed WResourceManager=="); } JQuad * WResourceManager::RetrieveCard(MTGCard * card, int style, int submode){ //Cards are never, ever resource managed, so just check cache. + if(!card) + return NULL; submode = submode | TEXTURE_SUB_CARD; string filename = card->getSetName(); filename += "/"; filename += card->getImageName(); - JQuad * jq = RetrieveQuad(filename,0,0,0,0,filename,style,submode|TEXTURE_SUB_5551); + JQuad * jq = RetrieveQuad(filename,0,0,0,0,"",style,submode|TEXTURE_SUB_5551); if(jq){ jq->SetHotSpot(jq->mTex->mWidth / 2, jq->mTex->mHeight / 2); @@ -335,9 +365,8 @@ void WResourceManager::Release(JQuad * quad){ break; } - //Releasing a quad doesn't release the associated texture-- it might be needed later. - //if(it != textureWCache.cache.end() && it->second) - // textureWCache.RemoveItem(it->second,false); //won't remove locked. + if(it != textureWCache.cache.end() && it->second) + textureWCache.RemoveItem(it->second,false); //won't remove locked. } void WResourceManager::ClearMisses(){ @@ -400,6 +429,9 @@ JTexture * WResourceManager::RetrieveTexture(string filename, int style, int sub case CACHE_ERROR_404: debugMessage = "File not found: "; break; + case CACHE_ERROR_BAD_ALLOC: + debugMessage = "Out of memory: "; + break; case CACHE_ERROR_BAD: debugMessage = "Cache bad: "; break; @@ -892,10 +924,6 @@ bool WCache::RemoveOldest(){ } if(oldest != cache.end() && oldest->second && !oldest->second->isLocked()){ - unsigned long isize = oldest->second->size(); - cacheSize -= isize; - totalSize -= isize; - cacheItems--; #if defined DEBUG_CACHE lastExpired = oldest->first; #endif @@ -915,13 +943,8 @@ void WCache::Clear(){ next = it; next++; - if(it->second){ - unsigned long isize = it->second->size(); - totalSize -= isize; - cacheSize -= isize; + if(it->second) Delete(it->second); - cacheItems--; - } cache.erase(it); } for(it = managed.begin(); it != managed.end();it=next){ @@ -942,11 +965,7 @@ void WCache::ClearUnlocked(){ next++; if(it->second && !it->second->isLocked()){ - unsigned long isize = it->second->size(); - totalSize -= isize; - cacheSize -= isize; Delete(it->second); - cacheItems--; cache.erase(it); } else if(!it->second){ @@ -983,6 +1002,19 @@ void WCache::Resize(unsigned long size, int items){ else maxCached = items; } + +template +cacheItem* WCache::Recycle(){ + typename vector::iterator it = garbage.begin(); + if(it == garbage.end()) + return NULL; + + cacheItem * item = (*it); + garbage.erase(it); + + return item; +} + template cacheItem* WCache::AttemptNew(string filename, int submode){ if(submode & CACHE_EXISTING){ //Should never get this far. @@ -990,24 +1022,46 @@ cacheItem* WCache::AttemptNew(string filename, int submo return NULL; } - cacheItem* item = NEW cacheItem; + cacheItem* item = NULL; - mError = CACHE_ERROR_NONE; + item = Recycle(); + + if(item == NULL){ + try{ + item = NEW cacheItem; + mError = CACHE_ERROR_NONE; + } + catch(std::bad_alloc){ + SAFE_DELETE(item); + } + } if(item == NULL || !item->Attempt(filename,submode,mError)){ //No such file. Fail. if(item && mError == CACHE_ERROR_404){ - Delete(item); + if(garbage.size() < MAX_CACHE_GARBAGE){ + item->Trash(); + garbage.push_back(item); + } + else + SAFE_DELETE(item); + return NULL; } - for(int attempt=0;attempt<10;attempt++){ if(!RemoveOldest()) break; - if(!item) - item = NEW cacheItem ; + if(!item){ + try{ + item = NEW cacheItem; + } + catch(std::bad_alloc){ + SAFE_DELETE(item); + continue; + } + } if(item && item->Attempt(filename,submode,mError)) break; @@ -1024,14 +1078,29 @@ cacheItem* WCache::AttemptNew(string filename, int submo //Worst cache scenerio. Clear every cache we've got. if(!item || !item->isGood()){ resources.ClearUnlocked(); - if(!item) item = NEW(cacheItem); + if(!item){ + try{ + item = NEW(cacheItem); + } + catch(std::bad_alloc){ + mError = CACHE_ERROR_BAD_ALLOC; + SAFE_DELETE(item); + return NULL; + } + } item->Attempt(filename,submode,mError); } } if(item && !item->isGood()){ - Delete(item); + if(garbage.size() < MAX_CACHE_GARBAGE){ + item->Trash(); + garbage.push_back(item); + } + else + SAFE_DELETE(item); mError = CACHE_ERROR_BAD; + return NULL; } else mError = CACHE_ERROR_NONE; @@ -1194,9 +1263,16 @@ cacheItem * WCache::Get(string id, int style, int submod //Space in cache, make new texture item = AttemptNew(id,submode); - //Couldn't make new item. + //Couldn't make GOOD new item. if(item && !item->isGood()) - Delete(item); + { + if(garbage.size() < MAX_CACHE_GARBAGE){ + item->Trash(); + garbage.push_back(item); + } + else + SAFE_DELETE(item); + } } if(style == RETRIEVE_MANAGE){ @@ -1216,7 +1292,7 @@ cacheItem * WCache::Get(string id, int style, int submod //Succeeded in making a new item. if(item){ - unsigned long isize =item->size(); + unsigned long isize = item->size(); totalSize += isize; mError = CACHE_ERROR_NONE; @@ -1225,9 +1301,6 @@ cacheItem * WCache::Get(string id, int style, int submod cacheSize += isize; } - item->lock(); - Cleanup(); //Strictly enforce limits. - item->unlock(); return item; } @@ -1272,14 +1345,21 @@ WCache::~WCache(){ if(!it->second) continue; - Delete(it->second); + //Delete(it->second); + SAFE_DELETE(it->second); } for(it=managed.begin();it!=managed.end();it++){ if(!it->second) continue; - Delete(it->second); + //Delete(it->second); + SAFE_DELETE(it->second); + } + + typename vector::iterator g; + for(g=garbage.begin();g!=garbage.end();g++){ + SAFE_DELETE(*g); } } @@ -1346,11 +1426,7 @@ bool WCache::RemoveItem(cacheItem * item, bool force){ break; } if(it != cache.end() && it->second && (force || !it->second->isLocked())){ - unsigned long isize = it->second->size(); - totalSize -= isize; - cacheSize -= isize; - cacheItems--; #if defined DEBUG_CACHE lastRemoved = it->first; #endif @@ -1377,7 +1453,7 @@ bool WCache::UnlinkCache(cacheItem * item){ it->second = NULL; unsigned long isize = item->size(); - cacheSize-=isize; + cacheSize -= isize; cacheItems--; cache.erase(it); return true; @@ -1398,7 +1474,22 @@ bool WCache::Delete(cacheItem * item){ if(maxCached == 0) item->Nullify(); - SAFE_DELETE(item); + unsigned long isize = item->size(); + totalSize -= isize; + cacheSize -= isize; +#ifdef DEBUG_CACHE + if(cacheItems == 0) + OutputDebugString("cacheItems out of sync.\n"); +#endif + + cacheItems--; + + if(garbage.size() > MAX_CACHE_GARBAGE) + SAFE_DELETE(item); + else{ + item->Trash(); + garbage.push_back(item); + } return true; } @@ -1419,12 +1510,8 @@ bool WCache::Release(cacheActual* actual){ if(it->second){ it->second->unlock(); //Release one lock. if(it->second->isLocked()) - return true; //Still locked, won't delete. + return true; //Still locked, won't delete, not technically a failure. - unsigned long isize = it->second->size(); - totalSize -= isize; - cacheSize -= isize; - cacheItems--; #if defined DEBUG_CACHE lastReleased = it->first; #endif