1// ============================================================= 2// This (poorly named) squirrel file contains the code to handle interaction with map objects. 3// It is also the file that handles the story-related special events. 4// 5 6// Some definitions. Maybe this should live in its own file. 7MD2_STAND <- 0; 8MD2_RUN <- 1; 9MD2_ATTACK <- 2; 10MD2_PAIN1 <- 3; 11MD2_PAIN2 <- 4; 12MD2_PAIN3 <- 5; 13MD2_JUMP <- 6; 14MD2_FLIP <- 7; 15MD2_SALUTE <- 8; 16MD2_TAUNT <- 9; 17MD2_WAVE <- 10; 18MD2_POINT <- 11; 19MD2_CRSTAND <- 12; 20MD2_CRWALK <- 13; 21MD2_CRATTACK <- 14; 22MD2_CRPAIN <- 15; 23MD2_CRDEATH <- 16; 24MD2_DEATH1 <- 17; 25MD2_DEATH2 <- 18; 26MD2_DEATH3 <- 19; 27 28// weather constants 29WEATHER_CLEAR <- 0 30WEATHER_RAIN <- 1 31WEATHER_THUNDER <- 2 32WEATHER_FOG <- 4 33 34// Called when entering map (before pressing ok) 35function enterMap( mapName ) { 36 print( "Welcome to S.C.O.U.R.G.E.: Heroes of Lesser Renown\n" ); 37 // print( "v" + scourgeGame.getVersion() + "\n" ); 38 print( "v" + scourgeGame.getVersion() + "\n" ); 39 print( "You are on the " + mapName + " map.\n" ); 40 print( "Chapter=" + scourgeGame.getMission().getChapter() + " Depth=" + scourgeGame.getMission().getDungeonDepth() + "\n" ); 41 42 if( scourgeGame.getMission().isStoryLineMission() && !scourgeGame.getMission().isReplayMap() ) { 43 switch( scourgeGame.getMission().getChapter() ) { 44 case 5: initChapter6(); break; 45 case 7: initChapter8(); break; 46 case 8: initChapter9(); break; 47 case 9: initChapter10(); break; 48 case 10: initChapter11(); break; 49 case 11: initChapter12(); break; 50 } 51 } 52} 53 54// Called when entering map (after pressing ok) 55function mapStarting( mapName ) { 56 if( mapName == "hq" ) { 57 startHqMovie(); 58 } 59} 60 61// Called when exiting map 62function exitMap( mapName ) { 63 print( "Ending level.\n" ); 64} 65 66function testMyco() { 67 i <- 0; 68 for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) { 69 if( scourgeGame.getMission().getCreature(i).getMonsterType() == "Mycotharsius the Mad" ) { 70 scourgeGame.getMission().getCreature(i).startConversation(); 71 break; 72 } 73 } 74} 75 76// Called when a creature dies (before it turns into a "corpse" container.) 77function creatureDeath( creature ) { 78 if( creature.getMonsterType() == "Mycotharsius the Mad" ) { 79 // Myco. starts a conversation before he dies, revealing much... 80 scourgeGame.getMission().setCompleted( true ); 81 creature.startConversation( creature ); 82 } else if( creature.getMonsterType() == "Mothrazu Pain Incarnate" ) { 83 scourgeGame.getMission().setCompleted( true ); 84 scourgeGame.showTextMessage( _( "The creature once known as Mothrazu sinks to one knee... Her breath comes in sharp gasps, as she growls:||\"I curse you humans...You may have defeated me but by Amod's grace, I still have one task left...\"||She reaches into a pouch and throws something small and silvery into the grove of trees at the center of the room.||\"You will never find it... Karzul's gift will mature and continue where I failed. May the plants be merciful to your malevolent souls... Amod! I am close...\"||With that Mothrazu passes from this world." ) ); 85 } else if( creature.getMonsterType() == "Karzul Agmordexu" ) { 86 startGameEndMovie(); 87 } 88 return true; 89} 90 91function decideAction( creature ) { 92 if( creature.getMonsterType() == "Karzul Agmordexu" ) { 93 if( creature.getHp().tofloat() <= 150 ) { 94 // karzul can save 6 times 95 key <- encodeKeyForCreature( creature, "Karzul.save" ); 96 value <- scourgeGame.getValue( key ); 97 if( value == null ) value = "0"; 98 99 numValue <- value.tointeger(); 100 print( "numValue=" + numValue.tostring() + "\n" ); 101 102 if( numValue < 10 ) { 103 print( "healing!\n" ); 104 scourgeGame.setValue( key, ( numValue + 1 ).tostring() ); 105 106 // heal self via the conduit 107 scourgeGame.printMessage( _( "Karzul uses his infernal conduit and heals his wounds!" ) ); 108 creature.setHp( creature.getHp() + ( rand() * 50.0 / RAND_MAX ).tointeger() ); 109 scourgeGame.getMission().setMapEffect( creature.getX(), creature.getY(), 3, // map location 110 "EFFECT_TELEPORT", // effect 111 4, 4, // base size 112 0, // delay 113 false, // forever 114 0, 0, 0, // offset 115 1.0, 0.05, 0.25 // color 116 ); 117 118 i <- 0; 119 minion_count <- 0; 120 minion_type <- "Cerxezu Demon Lord"; 121 max_minion_count <- 3; 122 minion <- null; 123 dead_mod <- scourgeGame.getStateModByName( "dead" ); 124 for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) { 125 minion = scourgeGame.getMission().getCreature( i ); 126 if( minion.getSummoner() == creature && !minion.getStateMod( dead_mod ) ) { 127 minion_count++; 128 } 129 } 130 131 print( "minions=" + minion_count.tostring() + "\n" ); 132 if( minion_count < max_minion_count ) { 133 print( "summoning!\n" ); 134 // fixme: should count number of helpers 135 scourgeGame.printMessage( _( "Karzul commands his minions to surge forth and destroy his attackers!" ) ); 136 for( i = 0; i < max_minion_count - minion_count; i++ ) { 137 minion = creature.summon( minion_type, 304, 433, 351, 464 ); 138 print( "new minion at: " + minion.getX().tostring() + "," + minion.getY().tostring() + "\n"); 139 } 140 } 141 return true; 142 } 143 } 144 } 145 return false; 146} 147 148// return true if the click was handled from squirrel 149function useShape( x, y, z ) { 150 //print( "useShape:: x=" + x + " y=" + y + " z=" + z + " chapter=" + scourgeGame.getMission().getChapter() + " depth=" + scourgeGame.getMission().getDungeonDepth() + "\n" ); 151 shape <- scourgeGame.getMission().getShape( x, y, z ); 152 if( shape != null ) { 153 print( "Shape used: " + shape + "\n" ); 154 print( "Depth: " + scourgeGame.getMission().getDungeonDepth() + "\n" ); 155 if( scourgeGame.getMission().getShape( x, y, 6 ) == "RED_TELEPORTER" ) { 156 if( scourgeGame.getMission().getDungeonDepth() == 0 ) { 157 print( "...going down..." ); 158 scourgeGame.getMission().descendDungeon( x, y, z ); 159 } else { 160 print( "...going up..." ); 161 scourgeGame.getMission().ascendDungeon( x, y, z ); 162 } 163 return true; 164 } else if( shape == "TREE-EMERIL-TRUNK" || shape == "TREE-EMERIL-TOP" ) { 165 handleTreeOfEmeril(); 166 return true; 167 } else if( shape == "EW_DOOR" && 168 x == 351 && y == 396 && 169 scourgeGame.getMission().getDungeonDepth() == 0 && 170 scourgeGame.getMission().getChapter() == 11 ) { 171 startChapter12Movie(); 172 return false; 173 } 174 } 175 return false; 176} 177 178// deities from spells.txt 179deities <- [ 180 "Unamoin", // Confrontation 181 "Soroughoz", // Ambush Trickery and Deceit 182 "Xelphate", // History and Lore 183 "Garzul-Meg-Aonrod", // Life and Death, 184 "Minirmuir", // Divine Awareness 185 "Amod-Rheinur" // Nature 186]; 187 188 189// Different actions based on pool's and player's deity 190// Some combination does good, some does bad stuff... 191function usePool( x, y, z ) { 192 print( "Clicked on x=" + x + " y=" + y + " z=" + z + "\n" ); 193 deity <- scourgeGame.getDeityLocation( x, y, z ); 194 print( "Deity=" + deity + "\n" ); 195 196 player <- scourgeGame.getPlayer(); 197 playersDeity <- player.getDeity(); 198 print( "player's deity is: " + playersDeity + "\n" ); 199 200 i <- 0; 201 deityIndex <- -1; 202 oppositeDeity <- null; 203 for( i = 0; i < deities.len(); i++ ) { 204 if( deity == deities[i] ) { 205 // a cheap way of calc. the opposite deity. 206 // only works for an even numbered pantheon. :-) 207 oppositeDeity = deities[ deities.len() - 1 - i ]; 208 deityIndex = i; 209 break; 210 } 211 } 212 if( deityIndex == -1 ) { 213 // ERROR: something changed in spells.txt 214 print( "*** Error: unknonw deity: " + deity + " did something change in data/world/spells.txt?" ); 215 return false; 216 } 217 218 print( "Opposite deity=" + oppositeDeity ); 219 220 helped <- false; 221 if( deity == playersDeity ) { 222 scourgeGame.printMessage( format( _( "The mighty lord %s reaches towards you," ), deity ) ); 223 if( !incrementDailyCount( player, "deity.help.lastDateUsed", 3 ) ) { 224 scourgeGame.playSound("pool-canthelp"); 225 scourgeGame.printMessage( _( "...alas, the deity can aid you no more today." ) ); 226 } else { 227 helped = true; 228 player.setHp( player.getHp() + 229 ( rand() * 230 ( 2.0 * player.getLevel().tofloat() ) / 231 RAND_MAX ).tointeger() + 1 ); 232 scourgeGame.playSound("pool-helped"); 233 scourgeGame.printMessage( _( "...and fills your spirit with energy." ) ); 234 } 235 } else if( oppositeDeity == playersDeity ) { 236 scourgeGame.printMessage( format( _( "Your presence angers the mighty lord %s!" ), deity ) ); 237 player.takeDamage( ( rand() * 238 ( 2.0 * player.getLevel().tofloat() ) / 239 RAND_MAX ) + 1.0 ); 240 scourgeGame.playSound("pool-punished"); 241 scourgeGame.printMessage( _( "...the deity's wrath scours your flesh!" ) ); 242 } else { 243 scourgeGame.playSound("pool-ignored"); 244 scourgeGame.printMessage( format( _( "The mighty lord %s ignores you." ), deity ) ); 245 } 246 247 // deity specific actions 248 if( helped ) { 249 mods <- []; 250 modIndex <- 0; 251 switch( deityIndex ) { 252 case 0: // unamoin, confrontation 253 player.setStateMod( scourgeGame.getStateModByName( "empowered" ), true ); 254 player.setStateMod( scourgeGame.getStateModByName( "ac_protected" ), true ); 255 break; 256 case 1: // Soroughoz, ambush, trickery and deceit 257 player.setStateMod( scourgeGame.getStateModByName( "blessed" ), true ); 258 player.setStateMod( scourgeGame.getStateModByName( "magic_protected" ), true ); 259 break; 260 case 2: // Xelphate, history & lore 261 mods = [ "drunk", "poisoned", "cursed" ]; 262 for( i = 0; i < mods.len(); i++ ) { 263 modIndex = scourgeGame.getStateModByName( mods[i] ); 264 if( player.getStateMod( modIndex ) ) player.setStateMod( modIndex, false ); 265 } 266 break; 267 case 3: // Garzul-Meg-Aonrod, life-death 268 mods = [ "possessed", "blinded", "paralysed" ]; 269 for( i = 0; i < mods.len(); i++ ) { 270 modIndex = scourgeGame.getStateModByName( mods[i] ); 271 if( player.getStateMod( modIndex ) ) player.setStateMod( modIndex, false ); 272 } 273 break; 274 case 4: // Minirmuir, Divine Awareness 275 player.setMp( player.getMp() + 276 ( rand() * 277 ( 2.0 * player.getLevel().tofloat() ) / 278 RAND_MAX ).tointeger() + 1 ); 279 break; 280 case 5: // Amod-Rheinur, nature 281 player.setThirst( 10 ); 282 player.setHunger( 10 ); 283 break; 284 } 285 } 286 287 // FIXME: sacrifizing money and items 288 289 return true; 290} 291 292// ============================================================= 293// Item events: they're only called for party members 294// 295function equipItem( creature, item ) { 296 //print( "ITEM EVENT: equipItem, creature: " + creature.getName() + " item: " + item.getName() + "\n" ); 297} 298 299function doffItem( creature, item ) { 300 //print( "ITEM EVENT: doffItem, creature: " + creature.getName() + " item: " + item.getName() + "\n" ); 301} 302 303function startBattleWithItem( creature, item ) { 304 //print( "ITEM EVENT: startBattleWithItem, creature: " + creature.getName() + " item: " + item.getName() + "\n" ); 305} 306 307// assume the global var "damage" is defined as for skills 308function useItemInAttack( creature, item ) { 309 if( item.getName() == "Brand of Iconoclast" ) { 310 useBrandOfIconoclast( creature, item ); 311 } 312} 313 314// assume the global var "armor" is defined as for skills 315function useItemInDefense( creature, item ) { 316 print( "useItemInDefense, item=" + item.getName() + "\n" ); 317} 318 319// assume the global var "damage" exists and contains the current amount of 320// damage caused by this weapon to attacker.getTargetCreature() 321// Change the value of damage to be more or less depending on items (etc) 322// held/equipped by the attacker or the target. 323// 324// Note: item can be null if attack is with bare hands 325function damageHandler( attacker, item ) { 326 if( attacker.getTargetCreature() != null ) { 327 equippedItem <- attacker.getTargetCreature().getEquippedItem( 4 ); 328 if( equippedItem != null ) { 329 if( equippedItem.getName() == "Cloak of Safe Passage" ) damageHandlerCloakSafePass( attacker, item ); 330 } 331 } 332} 333 334// assume the global var "spellDamage" exists and contains the current amount of 335// damage caused by this spell to caster.getTargetCreature() 336// Change the value of spellDamage to be more or less depending on items (etc) 337// held/equipped by the caster or the target. 338function spellDamageHandler( caster, spell ) { 339 if( caster.getTargetCreature() != null ) { 340 item <- caster.getTargetCreature().getEquippedItem( 4 ); 341 if( item != null ) { 342 if( item.getName() == "Cloak of Hateful Vengeance" ) spellDamageHandlerCloakHateVen( caster, spell ); 343 } 344 } 345} 346 347// The waitHandlerXYZ functions allow you to modify the 'wait' time of the 348// item, spell or skill used in a combat turn. 349// Assumem that a global variable named 'turnWait' exists. Change it to the 350// desired new value, or leave as is if no change is needed. 351function waitHandlerSkill( attacker, skillName ) { 352// print( "waitHandlerSkill: " + attacker.getName() + " wait=" + turnWait + "\n" ); 353} 354 355function waitHandlerSpell( caster, spell ) { 356// print( "waitHandlerSpell: " + caster.getName() + " wait=" + turnWait + "\n" ); 357 if( caster.hasCapability( "Speedy Casting" ) == true ) { 358 turnWait = turnWait * 0.75; 359 scourgeGame.printMessage( format( _( "%s conjures up magic with blinding speed!" ), caster.getName() ) ); 360 } 361} 362 363// if item is null, it's a bare-handed attack 364function waitHandlerItem( attacker, item ) { 365// print( "waitHandlerItem: " + attacker.getName() + " wait=" + turnWait + "\n" ); 366} 367 368// ============================================================= 369// Conversation methods 370// 371 372/** 373 * Called when conversing with someone. 374 * @param creature creature the name or type of the creature (npc) you are talking to 375 * @param question the first keyphrase in the list that was clicked (Look at the maps/*.cfg files for examples) 376 * @return the answer string or null for no special handling 377 */ 378function converse( creature, question ) { 379 print( "Creature=" + creature.getName() + " question:" + question + "\n" ); 380 381 // Orhithales will not give you information until the armor has been recovered 382 if( creature.getMonsterType() == "Orhithales Grimwise" && 383 !( scourgeGame.getMission().isCompleted() ) && 384 question == "SQ_DRAGONSCALE_ARMOR" ) { 385 return _( "Yes, yes... quite so... carry on!" ); 386 } else if( creature.getMonsterType() == "Sabien Gartu" ) { 387 if( !( scourgeGame.getMission().isCompleted() ) && 388 scourgeGame.getMission().getChapter() != 7 && 389 question == "SQ_LOCKED_DOOR" ) { 390 scourgeGame.getMission().setCompleted(); 391 } else if( scourgeGame.getMission().getChapter() == 7 ) { 392 if( question == "SQ_AFTER" ) { 393 // remove map block at 294,223 to make door accessible 394 scourgeGame.getMission().removeMapPosition( 294, 223, 0 ); 395 } 396 } 397 } else if( creature.getMonsterType() == "Karzul Agmordexu" && 398 !( scourgeGame.getMission().isCompleted() ) && 399 question == "SQ_SERVES" ) { 400 scourgeGame.getMission().setCompleted(); 401 } else if( creature.getMonsterType() == "Positive Energy of Hornaxx" ) { 402 if( question == "SQ_UNAMOIN" ) { 403 storePartyLevel(); 404 } else if( question == "SQ_TOKENS" ) { 405 assignAntimagicItems(); 406 } 407 } else if( creature.getMonsterType() == "Mothrazu" && 408 question == "SQ_DOOM" ) { 409 mothrazuTransforms( creature ); 410 } else if( creature.getMonsterType() == "Spawn of Arcanex" ) { 411 if( !( scourgeGame.getMission().isCompleted() ) && 412 question == "SQ_KARZUL" ) { 413 scourgeGame.getMission().setCompleted(); 414 } 415 } else if( creature.getMonsterType() == "Nightlord" && question == "ready" ) { 416 teleportPartyToSurface(); 417 } 418 return null; 419} 420 421function teleportPartyToSurface() { 422 // conversation ends 423 scourgeGame.endConversation(); 424 425 // summon help. todo: use this value once on the surface 426 scourgeGame.setValue( "guardians_summoned", "true" ); 427 428 // nightwards depart 429 430 // ascend! 431 scourgeGame.ascendToSurface(); 432} 433 434function mothrazuTransforms( creature ) { 435 scourgeGame.endConversation(); 436 replacement <- scourgeGame.getMission(). 437 replaceCreature( creature, 438 "Mothrazu Pain Incarnate" ); 439 // statemod: 0,1,2,3,4 and 11 (blessed, empowered, enraged, ac_protected, magic_protected and invisible) 440 replacement.setStateMod( 0, true ); 441 replacement.setStateMod( 1, true ); 442 replacement.setStateMod( 2, true ); 443 replacement.setStateMod( 3, true ); 444 replacement.setStateMod( 4, true ); 445 replacement.setStateMod( 11, true ); 446} 447 448// ============================================================= 449// Specific item handling 450function useBrandOfIconoclast( creature, item ) { 451 if( creature.getTargetCreature() != null && 452 creature.getTargetCreature().getMaxMp() > 0 ) { 453 scourgeGame.printMessage( _( "...Brand of Iconoclast growls in a low tone..." ) ); 454 delta <- ( damage / 100.0 ) * 10.0; 455 damage += delta; 456 if( delta.tointeger() > 0 ) { 457 scourgeGame.printMessage( format( _( "...damage is increased by %d pts!" ), delta.tointeger() ) ); 458 } 459 } 460} 461 462// spell damage reduction when wearing the Cloak of Vengeance 463function spellDamageHandlerCloakHateVen( caster, spell ) { 464 if( spell.getDeity() == "Unamoin" && damage > 0 ) { 465 466 delta <- ( damage / 100.0 ) * 15.0; 467 damage += delta; 468 if( delta.tointeger() > 0 ) { 469 scourgeGame.printMessage( format( _( "...damage is reduced by %d pts! (Cloak of Hateful Vengeance)" ), delta.tointeger() ) ); 470 } 471 472 incrementCloakHateVenUse( caster.getTargetCreature() ); 473 } 474} 475 476function incrementCloakHateVenUse( target ) { 477 key <- encodeKeyForCreature( target, "CloakOfHatefulVengeance" ); 478 value <- scourgeGame.getValue( key ); 479 if( value == null ) numValue <- 0; 480 else numValue <- value.tointeger(); 481 numValue++; 482 if( numValue >= 100 ) { 483 // FIXME: do something... cloak of hateful vengeance was used 100 times 484 scourgeGame.printMessage( "FIXME: do something! Cloak of Hateful Vengeance was used 100 times." ); 485 } 486 print( "Cloak of hateful vengeance was used " + numValue + " times.\n" ); 487 scourgeGame.setValue( key, numValue.tostring() ); 488} 489 490function damageHandlerCloakSafePass( attacker, item ) { 491 if( damage > 0 ) { 492 delta <- ( damage / 100.0 ) * 10.0; 493 damage += delta; 494 if( delta.tointeger() > 0 ) { 495 scourgeGame.printMessage( format( _( "...damage is reduced by %d pts! (Cloak of Safe Passage)" ), delta.tointeger() ) ); 496 } 497 } 498} 499 500// slow method, oh well 501function findCreatureByType( name ) { 502 i <- 0; 503 creature <- null; 504 for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) { 505 creature = scourgeGame.getMission().getCreature( i ); 506 if( creature.getMonsterType() == name ) { 507 return creature; 508 } 509 } 510 return null; 511} 512 513function dumpCreatures() { 514 i <- 0; 515 creature <- null; 516 for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) { 517 creature = scourgeGame.getMission().getCreature( i ); 518 print("i=" + i.tostring() + " creature=" + creature.getName() + " type=" + creature.getMonsterType() + "\n"); 519 } 520} 521 522function initChapter6() { 523 // lock the door 524 if( scourgeGame.getMission().getDungeonDepth() == 3 ) { 525 scourgeGame.getMission().setDoorLocked( 292, 209, 0, true ); 526 } 527} 528 529function initChapter8() { 530 // modify sabien's intro text 531 i <- 0; 532 if( scourgeGame.getMission().getDungeonDepth() == 0 ) { 533 534 // unlock the door 535 scourgeGame.getMission().setDoorLocked( 292, 209, 0, false ); 536 537 for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) { 538 if( scourgeGame.getMission().getCreature( i ).getMonsterType() == "Sabien Gartu" ) { 539 scourgeGame.getMission().getCreature( i ).setIntro( "SQ_CHAPTER_8" ); 540 break; 541 } 542 } 543 } else if( scourgeGame.getMission().getDungeonDepth() == 1 ) { 544 // everyone is cursed and poisoned 545 i <- 0; 546 for( i = 0; i < scourgeGame.getPartySize(); i++ ) { 547 // if not dead 548 if( !( scourgeGame.getPartyMember( i ).getStateMod( 13 ) ) ) { 549 // poisoned 550 scourgeGame.getPartyMember( i ).setStateMod( 6, true ); 551 // cursed 552 scourgeGame.getPartyMember( i ).setStateMod( 7, true ); 553 } 554 } 555 556 scourgeGame.showTextMessage( _( "You find yourself on a barren plain. The air is thick with moisture and very still. The bleak ground appears to emit a cancerous odor like the smell of death on a roadside cadaver. A sudden rush of despair hangs over you, clouding your senses... Is this the end? The tortured screams of unseen thousands drifts from beyond the nearest door. On this molten landscape filled with hopelessness and horror, even moving around seems to require an extra effort." ) ); 557 } 558} 559 560function initChapter9() { 561 i <- 0; 562 if( scourgeGame.getMission().getDungeonDepth() == 0 ) { 563 564 s <- getChapter9Intro(); 565 if( s != null ) { 566 for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) { 567 if( scourgeGame.getMission().getCreature( i ).getMonsterType() == "Positive Energy of Hornaxx" ) { 568 scourgeGame.getMission().getCreature( i ).setIntro( s ); 569 } else if( scourgeGame.getMission().getCreature( i ).getMonsterType() == "Negative Energy of Hornaxx" ) { 570 scourgeGame.getMission().getCreature( i ).setIntro( "SQ_RETURN" ); 571 } 572 } 573 } 574 } 575} 576 577function getChapter9Intro() { 578 i <- 0; 579 for( i = 0; i < scourgeGame.getPartySize(); i++ ) { 580 key <- encodeKeyForCreature( scourgeGame.getPartyMember( i ), "hornaxx" ); 581 value <- scourgeGame.getValue( key ); 582 if( value != null ) { 583 numValue <- value.tointeger(); 584 if( scourgeGame.getPartyMember( i ).getLevel() > numValue ) { 585 return "SQ_RETURN_TRUE"; 586 } else { 587 return "SQ_RETURN_FALSE"; 588 } 589 } 590 } 591 return null; 592} 593 594antimagicItems <- [ 595 "Boots of antimagic binding", 596 "Antimagic foil hat", 597 "Antimagic chestplate" 598]; 599 600antimagicItemLocations <- [ 601 256, 1, 8 602]; 603 604function initChapter10() { 605 if( scourgeGame.getMission().getDungeonDepth() == 0 ) { 606 scourgeGame.showTextMessage( _( "The ancient walls appear to cave inward as if pushed on by the very roots of the forest from above. A metallic smell cuts the air and the noises echoing from the deep chill your bones. ||A grinding sound wells from beneath your feet as if the wheels of a great machine are turning. Could this be the contdown to Mothrazu's infernal plans? ||And as if that wasn't freeky enough, frequent quakes shake the dungeon..." ) ); 607 } 608 609 // poison party members without antimagic binding armor 610 i <- 0; 611 found <- false; 612 equippedItem <- null; 613 t <- 0; 614 for( i = 0; i < scourgeGame.getPartySize(); i++ ) { 615 found = false; 616 for( t = 0; t < antimagicItemLocations.len(); t++ ) { 617 equippedItem = scourgeGame.getPartyMember( i ).getEquippedItem( antimagicItemLocations[ t ] ); 618 if( equippedItem != null ) { 619 if( equippedItem.getName() == antimagicItems[ t ] ) { 620 found = true; 621 break; 622 } 623 } 624 } 625 if( !found ) { 626 scourgeGame.printMessage( format( _( "%s feels very ill suddenly." ), 627 scourgeGame.getPartyMember( i ).getName() ) ); 628 scourgeGame.getPartyMember( i ).setStateMod( 6, true ); 629 } 630 } 631 632 // start the earthquakes 633 scourgeGame.getMission().setQuakesEnabled( true ); 634} 635 636function storePartyLevel() { 637 i <- 0; 638 for( i = 0; i < scourgeGame.getPartySize(); i++ ) { 639 print( "storing for " + i + "\n" ); 640 key <- encodeKeyForCreature( scourgeGame.getPartyMember( i ), "hornaxx" ); 641 value <- scourgeGame.getValue( key ); 642 if( value == null ) { 643 print( "Storing level for " + scourgeGame.getPartyMember( i ).getName() + "\n" ); 644 scourgeGame.setValue( key, scourgeGame.getPartyMember( i ).getLevel().tostring() ); 645 } 646 } 647} 648 649function assignAntimagicItems() { 650 i <- 0; 651 t <- 0; 652 b <- false; 653 for( i = 0; i < scourgeGame.getPartySize(); i++ ) { 654 key <- encodeKeyForCreature( scourgeGame.getPartyMember( i ), "hornaxx-antimagic" ); 655 value <- scourgeGame.getValue( key ); 656 if( value == null ) { 657 // Assign items. 658 // The first player gets more more if not all party positions are filled in. 659 n <- 1; 660 if( i == 0 ) n = n + ( 4 - scourgeGame.getPartySize() ); 661 r <- 0; 662 for( r = 0; r < n; r++ ) { 663 scourgeGame.getPartyMember( i ).addToBackpackByName( antimagicItems[ t++ ] ); 664 if( t >= antimagicItems.len() ) t = 0; 665 } 666 scourgeGame.setValue( key, "true" ); 667 b = true; 668 } 669 } 670 if( b ) { 671 scourgeGame.getMission().setCompleted( true ); 672 } 673} 674 675function _( s ) { 676 r <- scourgeGame.getTranslatedString( s ); 677 return r; 678} 679 680function noop( s ) { 681 return s; 682} 683 684function initChapter11() { 685 if( scourgeGame.getMission().getDungeonDepth() == 0 ) { 686 scourgeGame.showTextMessage( _( "A baleful wind blows bringing the scent of slow vegetative decay. Off in the distance you glance a mighty tree, standing in the center of a barren plane of ashen stone.||No other plants dare intrude upon its territory and no animal life stirs near its accursed branches.||Above, clouds darken the sky as if to signal the long awaited fulfillment of a pending doom." ) ); 687 688 // Add creature for spawn of arcanex (need in order to converse w. tree) 689 // This has to be done each time the map is entered b/c npc-s aren't saved with the map. 690 //print( "Adding creature: count=" + scourgeGame.getMission().getCreatureCount() ); 691 scourgeGame.getMission().addCreature( 5, 5, 0, "Spawn of Arcanex" ); 692 scourgeGame.getMission().setMapConfig( "/maps/tree" ); 693 } 694} 695 696function initChapter12() { 697 if( scourgeGame.getMission().getDungeonDepth() == 0 ) { 698 699 scourgeGame.getMission().setMapEffect( 312, 446, 1, // map location 700 "EFFECT_SMOKE", // effect 701 1, 1, // base size 702 0, // delay 703 true, // forever 704 0, 0, 0, // offset 705 0.2, 0.2, 0.5 // color 706 ); 707 scourgeGame.getMission().setMapEffect( 317, 438, 1, // map location 708 "EFFECT_SMOKE", // effect 709 1, 1, // base size 710 0, // delay 711 true, // forever 712 0, 0, 0, // offset 713 0.2, 0.2, 0.5 // color 714 ); 715 scourgeGame.getMission().setMapEffect( 319, 455, 1, // map location 716 "EFFECT_SMOKE", // effect 717 1, 1, // base size 718 0, // delay 719 true, // forever 720 0, 0, 0, // offset 721 0.2, 0.2, 0.5 // color 722 ); 723 scourgeGame.getMission().setMapEffect( 331, 455, 1, // map location 724 "EFFECT_SMOKE", // effect 725 1, 1, // base size 726 0, // delay 727 true, // forever 728 0, 0, 0, // offset 729 0.2, 0.2, 0.5 // color 730 ); 731 scourgeGame.getMission().setMapEffect( 330, 438, 1, // map location 732 "EFFECT_SMOKE", // effect 733 1, 1, // base size 734 0, // delay 735 true, // forever 736 0, 0, 0, // offset 737 0.2, 0.2, 0.5 // color 738 ); 739 740 741 // reset some creatures 742 karzul <- findCreatureByType( "Karzul Agmordexu" ); 743 if( karzul != null ) { 744 while( karzul != null ) { 745 karzul.remove(); 746 karzul = findCreatureByType( "Karzul Agmordexu" ); 747 } 748 karzul <- scourgeGame.getMission().addCreature( 320, 449, 0, "Karzul Agmordexu" ); 749 karzul.setNpc( false ); // karzul attacks 750 751 if( scourgeGame.getValue( "guardians_summoned" ) == "true" ) { 752 norill <- findCreatureByType( "Norill" ); 753 while( norill != null ) { 754 norill.remove(); 755 norill = findCreatureByType( "Norill" ); 756 } 757 scourgeGame.getMission().addCreature( 338, 454, 0, "Norill" ); 758 759 sarrez <- findCreatureByType( "Sarrez" ); 760 while( sarrez != null ) { 761 sarrez.remove(); 762 sarrez = findCreatureByType( "Sarrez" ); 763 } 764 scourgeGame.getMission().addCreature( 305,454, 0, "Sarrez" ); 765 766 rolan <- findCreatureByType( "Rolan" ); 767 while( rolan != null ) { 768 rolan.remove(); 769 rolan = findCreatureByType( "Rolan" ); 770 } 771 scourgeGame.getMission().addCreature( 332,416, 0, "Rolan" ); 772 773 scourgeGame.setWeather( WEATHER_RAIN | WEATHER_THUNDER ); 774 775 scourgeGame.showTextMessage( _( "Under the pale sky like the blackened husk of a burned tree stands the demon. He calmly awaits your charge fully aware of its futility.||But a red streak lines the mountain tops to the east... is it dawn? Or is it a sign of hope from the gods? Looking around you notice you are no longer alone on the charred battlefield. Three tall warriors in archaic clothing appear as if from nowhere. The tallest one - their leader? - silently bows his head to you.||After this briefest of courtesies, he turns to face Karzul with a steely resolve." ) ); 776 } 777 } 778 } else if( scourgeGame.getMission().getDungeonDepth() == 2 ) { 779 //print( "chapter 12 map\n" ); 780 scourgeGame.getMission().setMapEffect( 296, 264, 2, // map location 781 "EFFECT_SMOKE", // effect 782 3, 3, // base size 783 0, // delay 784 true, // forever 785 0, 0, 0, // offset 786 0.3, 0.7, 0.3 // color 787 ); 788 scourgeGame.getMission().setMapEffect( 326, 264, 2, // map location 789 "EFFECT_SMOKE", // effect 790 3, 3, // base size 791 0, // delay 792 true, // forever 793 0, 0, 0, // offset 794 0.7, 0.3, 0.3 // color 795 ); 796 scourgeGame.getMission().setMapEffect( 311, 271, 2, // map location 797 "EFFECT_SMOKE", // effect 798 3, 3, // base size 799 0, // delay 800 true, // forever 801 0, 0, 0, // offset 802 0.3, 0.3, 0.7 // color 803 ); 804 scourgeGame.getMission().setMapEffect( 296, 278, 2, // map location 805 "EFFECT_SMOKE", // effect 806 3, 3, // base size 807 0, // delay 808 true, // forever 809 0, 0, 0, // offset 810 0.3, 0.7, 0.7 // color 811 ); 812 scourgeGame.getMission().setMapEffect( 326, 279, 2, // map location 813 "EFFECT_SMOKE", // effect 814 3, 3, // base size 815 0, // delay 816 true, // forever 817 0, 0, 0, // offset 818 0.7, 0.3, 0.7 // color 819 ); 820 821 // the nightwards depart 822 if( scourgeGame.getValue( "guardians_summoned" ) == "true" ) { 823 creature <- null; 824 i <- 0; 825 for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) { 826 creature = scourgeGame.getMission().getCreature( i ); 827 if( creature.isNpc() ) { 828 creature.setVisible( false ); 829 } 830 } 831 } 832 833 } 834} 835 836function outdoorMapCompleted( mapName ) { 837 print( "Customizing map: " + mapName + "\n" ); 838 if( scourgeGame.getMission().getChapter() == 10 && scourgeGame.getMission().isStoryLineMission() ) { 839 840 // level the area in the center 841 x <- 0; 842 y <- 0; 843 for( x = 250; x < 350; x++ ) { 844 for( y = 250; y < 350; y++ ) { 845 scourgeGame.getMission().setHeightMap( x, y, 3.0 ); 846 scourgeGame.getMission().removeMapPosition( x, y, 0 ); 847 // color the ground 848 } 849 } 850 851 // add the tree of emeril 852 scourgeGame.getMission().setMapPosition( 312, 288, 0, "TREE-EMERIL-TRUNK" ); 853 scourgeGame.getMission().setMapPosition( 300, 300, 12, "TREE-EMERIL-TOP" ); 854 855 // add decoration around tree 856 857 // link to cfg file (contains conversations) 858 859 860 } 861} 862 863function handleTreeOfEmeril() { 864 hasCronostar <- false; 865 i <- 0; 866 t <- 0; 867 item <- null; 868 print( "Looking for cronostar...\n" ); 869 for( i = 0; hasCronostar == false && i < scourgeGame.getPartySize(); i++ ) { 870 print( "\tparty member=" + i + "...\n" ); 871 for( t = 0; t < scourgeGame.getPartyMember( i ).getBackpackContentsCount(); t++ ) { 872 item = scourgeGame.getPartyMember( i ).getBackpackItem( t ); 873 if( item.getName() == "Cronostar" ) { 874 hasCronostar = true; 875 break; 876 } 877 } 878 } 879 print( "found it? " + ( hasCronostar ? "true" : "false" ) + "\n" ); 880 if( hasCronostar ) { 881 for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) { 882 print( "\tcreature=" + scourgeGame.getMission().getCreature(i).getMonsterType() + "\n" ); 883 if( scourgeGame.getMission().getCreature(i).getMonsterType() == "Spawn of Arcanex" ) { 884 print( "\t\tstarting conversation!\n" ); 885 scourgeGame.getMission().getCreature(i).startConversation(); 886 break; 887 } 888 } 889 } 890} 891