Update math.uc

Update math.uc

# math.uc - uCalc Transformation file
# This file was saved with uCalc Transform 2.96 on 6/17/2014 7:44:29 PM
# Comment: Converts math-related code from PowerBASIC to C++

ExternalKeywords: Exclude, Comment, Selected, ParentChild, FindMode, InputFile, OutputFile, BatchAction, SEND
ExternalKeywords: Highlight, ForeColor, BackColor, FontName, FontSize, FontStyle
ExternalKeywords: FilterEndText, FilterSeparator, FilterSort, FilterSortFunc, FilterStartText, FilterUnique, FilterTally

FindMode: Replace

# Definitions

# Search Criteria

Criteria: 0
Enabled: True
Exclude: False
Comment: Converts math-related code from PowerBASIC to C++
Selected: False
Highlight: True
ForeColor: ControlText
BackColor: Aqua
FontName:
FontSize:
FontStyle:
CaseSensitive: False
QuoteSensitive: True
CodeBlockSensitive: True
FilterEndText:
FilterSeparator: {#10}
FilterSort: False
FilterSortFunc:
FilterStartText:
FilterUnique: False
FilterTally: False
Min: 0
Max: -1
MinSoft: 0
MaxSoft: -1
BatchAction: Transform
InputFile:
OutputFile:
SEND:
StartAfter: 0
StopAfter: -1
SkipOver: False
ParentChild: 0
Pass: 0
PassOnce: True
Precedence: 0
RightToLeft: False

Criteria: 1
Find:
Replace: {@Var: Type As String}
         {@Note: rand & srand are in <cstdlib>, the others in <cmath>}
         {@Note: ToDo: \ eqv imp bin }

Criteria: 2
Comment: ^ (power)
Pass: 1

Criteria: 3
SkipOver: True
Find: ' {Comment:".*"}
Replace: [Skip over]

Criteria: 4
BackColor: Gold
Precedence: 100
Find: {x%} ^ {y%}  {@Note: precedence property set to 100}
Replace: pow({x}, {y})

Criteria: 5
Precedence: 60
Find: {x%} \ {y%}  {@Note: precedence property set to 60}
Replace: _round({x} / {y})

Criteria: 6
Precedence: 60
Find: {x%} mod {y%}
Replace: Long({x}) mod {y}

Criteria: 7
Precedence: 19
Find: {x%} Eqv {y%}
Replace: PB_EQV({x}, {y})

Criteria: 8
Precedence: 18
Find: {x%} Imp {y%}
Replace: PB_IMP({x}, {y})

Criteria: 9
Precedence: 20
Find: {x%} Xor {y%}
Replace: PB_XOR({x}, {y})

Criteria: 10
Precedence: 1
Find: To {etc%}
Replace: To {etc}

Criteria: 11
Find: If {cond%} Then
Replace: If {cond} Then

Criteria: 12
Find: {nl} {var:1} = {etc%}
Replace: {nl} {var} = {etc} {@Note: Must fix >=}

Criteria: 13
Comment: Bitwise AND and OR
Pass: 2

Criteria: 14
SkipOver: True
Find: ' {Comment:".*"}
Replace: [Skip over]

Criteria: 15
Comment: Bitwise AND and OR
BackColor: YellowGreen
Find: ({expr})
Replace: ({@Evaluate: Replace(Replace({expr}, "And", "&"), "Or", "|")})

Criteria: 16
Comment: Everything else
Pass: 3

Criteria: 17
SkipOver: True
Find: ' {Comment:".*"}
Replace: [Skip over]

Criteria: 18
Find: Mod
Replace: %

Criteria: 19
BackColor: Yellow
Find: Atn
Replace: atan

Criteria: 20
BackColor: Lime
Find: Sqr
Replace: sqrt

Criteria: 21
BackColor: Pink
Find: Cint
Replace: Integer

Criteria: 22
Find: Int(
Replace: __int64(

Criteria: 23
BackColor: Red
Find: Incr {var:1}
Replace: {var}++

Criteria: 24
BackColor: RoyalBlue
Find: Decr {var:1}
Replace: {var}--

Criteria: 25
Comment: Logical (short-circuit) AND
Find: And
Replace: &&

Criteria: 26
Comment: Logical (short-circuit) OR
BackColor: Purple
Find: Or
Replace: ||

Criteria: 27
Selected: True
BackColor: Green
Find: Not
Replace: ~

Criteria: 28
SkipOver: True
Find: #{metastatement:1} Not
Replace: [Skip over]

Criteria: 29
BackColor: Silver
Find: IsTrue {x%}  [{stop-: And | Or | Then | : }]
Replace: (({x}) != 0)

Criteria: 30
BackColor: SandyBrown
Find: IsFalse {x%} [{stop-: And | Or | Then | : }]
Replace: !({x})

Criteria: 31
BackColor: Violet
Find: <>
Replace: !=

Criteria: 32
Find: Randomize {number%}
Replace: srand({number})

Criteria: 33
Find: Rnd[()]
Replace: (rand() / RAND_MAX)

Criteria: 34
Find: Rnd({a%}, {b%})
Replace: (rand() % ({b}) + ({a}))

Criteria: 35
Find: Shift Right {ivar}, {countexpr%}
Replace: {ivar} = ({ivar} >> {countexpr})

Criteria: 36
Find: Shift Left {ivar}, {countexpr%}
Replace: {ivar} = ({ivar} << {countexpr})

Criteria: 37
Find: {func: Abs|Sin|Cos|Tan|Exp|Exp2|Log|Log2|Log10|Ceil}
Replace: {@Evaluate: LCase("{func}", "{'.*'}")}

Criteria: 38
Find: {func: Exp10 | Fix | Frac | Sgn}
Replace: PB_{@Evaluate: UCase("{func}", "{'.*'}")}

Criteria: 39
PassOnce: False
Find: {func: Min | Max}[{ {int: &} | {str: $} | {dbl: } }]
      ({args})
Replace: PB_{@Evaluate:
            Type = "(double)"
            IIf("{int}" <> "", Type = "(int)")
            IIf("{str}" <> "", Type = "(string)")
            UCase("{func}", "{'.*'}")
         }{int:_INT}{str:_STR}(ARGCOUNT({@Evaluate:
         Tally({args}, ",", Skip("({nest})"))+1}), {@Evaluate:
         Type + Replace({args}, ",", ", "+Type, Skip("({nest})"))})

Criteria: 40
Find: )()
Replace: ){@Note:
            because of problem "between = {etc#%}" in pass 1
            & Rnd which leaves a stray ()
         }

# End Search

# math.uc - uCalc Transformation file
# This file was saved with uCalc Transform 2.96 on 6/17/2014 7:44:29 PM
# Comment: Converts math-related code from PowerBASIC to C++

ExternalKeywords: Exclude, Comment, Selected, ParentChild, FindMode, InputFile, OutputFile, BatchAction, SEND
ExternalKeywords: Highlight, ForeColor, BackColor, FontName, FontSize, FontStyle
ExternalKeywords: FilterEndText, FilterSeparator, FilterSort, FilterSortFunc, FilterStartText, FilterUnique, FilterTally

FindMode: Replace

# Definitions

# Search Criteria

Criteria: 0
Enabled: True
Exclude: False
Comment: Converts math-related code from PowerBASIC to C++
Selected: False
Highlight: True
ForeColor: ControlText
BackColor: Aqua
FontName:
FontSize:
FontStyle:
CaseSensitive: False
QuoteSensitive: True
CodeBlockSensitive: True
FilterEndText:
FilterSeparator: {#10}
FilterSort: False
FilterSortFunc:
FilterStartText:
FilterUnique: False
FilterTally: False
Min: 0
Max: -1
MinSoft: 0
MaxSoft: -1
BatchAction: Transform
InputFile:
OutputFile:
SEND:
StartAfter: 0
StopAfter: -1
SkipOver: False
ParentChild: 0
Pass: 0
PassOnce: True
Precedence: 0
RightToLeft: False

Criteria: 1
Find:
Replace: {@Var: Type As String}
         {@Note: rand & srand are in <cstdlib>, the others in <cmath>}
         {@Note: ToDo: \ eqv imp bin }

Criteria: 2
Comment: ^ (power)
Pass: 1

Criteria: 3
SkipOver: True
Find: ' {Comment:".*"}
Replace: [Skip over]

Criteria: 4
BackColor: Gold
Precedence: 100
Find: {x%} ^ {y%}  {@Note: precedence property set to 100}
Replace: pow({x}, {y})

Criteria: 5
Precedence: 60
Find: {x%} \ {y%}  {@Note: precedence property set to 60}
Replace: _round({x} / {y})

Criteria: 6
Precedence: 60
Find: {x%} mod {y%}
Replace: Long({x}) mod {y}

Criteria: 7
Precedence: 19
Find: {x%} Eqv {y%}
Replace: PB_EQV({x}, {y})

Criteria: 8
Precedence: 18
Find: {x%} Imp {y%}
Replace: PB_IMP({x}, {y})

Criteria: 9
Precedence: 20
Find: {x%} Xor {y%}
Replace: PB_XOR({x}, {y})

Criteria: 10
Precedence: 1
Find: To {etc%}
Replace: To {etc}

Criteria: 11
Find: If {cond%} Then
Replace: If {cond} Then

Criteria: 12
Find: {nl} {var:1} = {etc%}
Replace: {nl} {var} = {etc}

Criteria: 13
Comment: Bitwise AND and OR
Pass: 2

Criteria: 14
SkipOver: True
Find: ' {Comment:".*"}
Replace: [Skip over]

Criteria: 15
Comment: Bitwise AND and OR
BackColor: YellowGreen
Find: ({expr})
Replace: ({@Evaluate: Replace(Replace({expr}, "And", "&"), "Or", "|")})

Criteria: 16
Comment: Everything else
Pass: 3

Criteria: 17
SkipOver: True
Find: ' {Comment:".*"}
Replace: [Skip over]

Criteria: 18
Find: Mod
Replace: %

Criteria: 19
BackColor: Yellow
Find: Atn
Replace: atan

Criteria: 20
BackColor: Lime
Find: Sqr
Replace: sqrt

Criteria: 21
BackColor: Pink
Find: Cint
Replace: Integer

Criteria: 22
Find: Int(
Replace: __int64(

Criteria: 23
BackColor: Red
Find: Incr {var:1}
Replace: {var}++

Criteria: 24
BackColor: RoyalBlue
Find: Decr {var:1}
Replace: {var}--

Criteria: 25
Comment: Logical (short-circuit) AND
Find: And
Replace: &&

Criteria: 26
Comment: Logical (short-circuit) OR
BackColor: Purple
Find: Or
Replace: ||

Criteria: 27
Selected: True
BackColor: Green
Find: Not
Replace: ~

Criteria: 28
SkipOver: True
Find: #{metastatement:1} Not
Replace: [Skip over]

Criteria: 29
BackColor: Silver
Find: IsTrue {x%}  [{stop-: And | Or | Then | : }]
Replace: (({x}) != 0)

Criteria: 30
BackColor: SandyBrown
Find: IsFalse {x%} [{stop-: And | Or | Then | : }]
Replace: !({x})

Criteria: 31
BackColor: Violet
Find: <>
Replace: !=

Criteria: 32
Find: Randomize {number%}
Replace: srand({number})

Criteria: 33
Find: Rnd[()]
Replace: (rand() / RAND_MAX)

Criteria: 34
Find: Rnd({a%}, {b%})
Replace: (rand() % ({b}) + ({a}))

Criteria: 35
Find: Shift Right {ivar}, {countexpr%}
Replace: {ivar} = ({ivar} >> {countexpr})

Criteria: 36
Find: Shift Left {ivar}, {countexpr%}
Replace: {ivar} = ({ivar} << {countexpr})

Criteria: 37
Find: {func: Abs|Sin|Cos|Tan|Exp|Exp2|Log|Log2|Log10|Ceil}
Replace: {@Evaluate: LCase("{func}", "{'.*'}")}

Criteria: 38
Find: {func: Exp10 | Fix | Frac | Sgn}
Replace: PB_{@Evaluate: UCase("{func}", "{'.*'}")}

Criteria: 39
PassOnce: False
Find: {func: Min | Max}[{ {int: &} | {str: $} | {dbl: } }]
      ({args})
Replace: PB_{@Evaluate:
            Type = "(double)"
            IIf("{int}" <> "", Type = "(int)")
            IIf("{str}" <> "", Type = "(string)")
            UCase("{func}", "{'.*'}")
         }{int:_INT}{str:_STR}(ARGCOUNT({@Evaluate:
         Tally({args}, ",", Skip("({nest})"))+1}), {@Evaluate:
         Type + Replace({args}, ",", ", "+Type, Skip("({nest})"))})

Criteria: 40
Find: )()
Replace: ){@Note:
            because of problem "between = {etc#%}" in pass 1
            & Rnd which leaves a stray ()
         }

# End Search


Update implicit-convert.uc

Update implicit-convert.uc

Various improvements (but doesn't change the code yet)

# implicit-convert.uc - uCalc Transformation file
# This file was saved with uCalc Transform 2.96 on 5/26/2014 5:41:37 PM
# Comment: Handles implicit data type conversions

ExternalKeywords: Exclude, Comment, Selected, ParentChild, FindMode, InputFile, OutputFile, BatchAction, SEND
ExternalKeywords: Highlight, ForeColor, BackColor, FontName, FontSize, FontStyle
ExternalKeywords: FilterEndText, FilterSeparator, FilterSort, FilterSortFunc, FilterStartText, FilterUnique, FilterTally

FindMode: Replace

# Definitions

# Search Criteria

Criteria: 0
Enabled: False
Exclude: False
Comment: Handles implicit data type conversions
Selected: False
Highlight: True
ForeColor: ControlText
BackColor: Aqua
FontName:
FontSize:
FontStyle:
CaseSensitive: False
QuoteSensitive: False
CodeBlockSensitive: True
FilterEndText:
FilterSeparator: {#10}
FilterSort: False
FilterSortFunc:
FilterStartText:
FilterUnique: False
FilterTally: False
Min: 0
Max: -1
MinSoft: 0
MaxSoft: -1
BatchAction: Transform
InputFile:
OutputFile:
SEND:
StartAfter: 0
StopAfter: -1
SkipOver: False
ParentChild: 0
Pass: 0
PassOnce: True
Precedence: 0
RightToLeft: False

Criteria: 1
Enabled: True
Highlight: False
Find:
Replace: {@Eval:
            Dim Size As Table = {
               "Byte", 1, "Word", 2, "Integer", 2, "Long", 4, "Dword", 4,
               "Single", 4, "Double", 8, "Extended", 10
            }
         }
         {@Define:
            Var: Def As String
            Var: Args As String
            Var: Before As String
            Var: After As String
            Var: UDT As Table
            Var: Size
            SyntaxArgL: {number} = {number:"([0-9]*\.)?[0-9]+(e[-+]?[0-9]+)?"}
         }
         {@Define::
            Token: \x27.* ~~ Properties: ucWhitespace
            Token: _.*\n ~~ Properties: ucWhitespace
         }

Criteria: 2
Comment: Inserts data type names in front of variabls and functions
Pass: 1

Criteria: 3
Enabled: True
Selected: True
Highlight: False
Find: {nl}[Declare] { Function | Sub } {name~:1} [Alias {alias}] ([{args%}]) [As {ftype:1=void}]
Replace: {@Exec:
            Args = Remove("{args}", "{ Optional | ByVal | ByRef | Ptr | () | {' *_.*\n *'} }")
            Before = Replace(Args, "{arg:1} As {type:1}", "{{arg}%}")
            After = Replace(Args, "{arg:1} As {type:1}", "##{type}({{arg}})")

            Def  = "Pass: 1 ~~ Syntax: {name}("+Before+")"
            Def += " ::= `{ftype}({name}(" + After + "))"
         }{@Define:: {@Eval: Def}}{Self}

Criteria: 4
Enabled: True
Highlight: False
Find: { Global | Local | Static | Dim | , | { ByVal | ByRef } } {var:1}[()] As {type:1}
Replace: {Self}{@Define:: Pass: 1 ~~ Syntax: {var} ::= `{type}({var})}

Criteria: 5
Enabled: True
Highlight: False
Find: {number}
Replace: `Double({number})

Criteria: 6
Enabled: True
Highlight: False
BackColor: RoyalBlue
Find: {q}{text}{q}
Replace: `StringLit({Self})

Criteria: 7
Enabled: True
Highlight: False
BackColor: Pink
Find: {func: Asc|InStr|Len|UBound|VarPtr|StrPtr|Dir|CurDir } ({args%})
Replace: `Long({func}({args}))

Criteria: 8
Enabled: True
Highlight: False
BackColor: SlateBlue
Find: {func:
         Mid|Left|Right|Remove|Extract|Space|Hex|Oct|Bin|Dir|Min|Max|
         Remain|UCase|LCase|Trim|LTrim|RTrim|Choose|Repeat
      }$({args%})
Replace: `String({func}$({args}))

Criteria: 9
Enabled: True
Find: {nl}${equate:1}
Replace: {Self}{@Define:: Pass: 1 ~~ Syntax: ${equate} ::= `String(${equate})}

Criteria: 10
Enabled: True
Find: {nl}$${equate:1}
Replace: {Self}{@Define:: Pass: 1 ~~ Syntax: $${equate} ::= `WString($${equate})}

Criteria: 11
Enabled: True
Find: {nl}%{equate:1}
Replace: {Self}{@Define:: Pass: 1 ~~ Syntax: %{equate} ::= `Long(%{equate})}

Criteria: 12
Enabled: True
Highlight: False
BackColor: Purple
SkipOver: True
Find: {nl} { Type | Union }
         {members+}
      End {TypeOrUnion}
Replace: [Skip over]

Criteria: 13
Enabled: True
BackColor: Khaki
SkipOver: True
Find: {nl}{ # | ! | ASM } {etc} {@Note: Skips metastatements, ASM}
Replace: [Skip over]

Criteria: 14
Comment: Convert
Pass: 2

Criteria: 15
Enabled: True
BackColor: Violet
PassOnce: False
Find: ##Asciiz(string({arg}))
Replace: `Asciiz({arg}.c_str())

Criteria: 16
Enabled: True
PassOnce: False
Find: `StringLit({arg})+`StringLit({arg})
Replace: `String(string({arg})+{arg})

Criteria: 17
Enabled: True
BackColor: CornflowerBlue
PassOnce: False
Find: `WString({arg}) + `String({arg})
Replace: `WString({arg}) + `WString(string({arg}))

Criteria: 18
Enabled: True
BackColor: SandyBrown
PassOnce: False
Find: Len(`String({arg}))
Replace: `Long(({arg}).length())

Criteria: 19
Enabled: True
BackColor: Gold
PassOnce: False
Find: Len(`LPCSTR({arg}))
Replace: `Long(strlen({arg}))

Criteria: 20
Enabled: True
PassOnce: False
Find: `{ Extended | Ext }
Replace: `Double

Criteria: 21
Comment: Highlights the inserted data type names
Pass: 3

Criteria: 22
Enabled: False
BackColor: Red
Find: ##{type:1}
Replace: {Self}

Criteria: 23
Enabled: False
Comment: This line is there to provide highlighting for clarity
Find: `{type:1}
Replace: {Self}

Criteria: 24
Enabled: True
PassOnce: False
Find: { ` | ## }{type:1}({arg})
Replace: {arg}

# End Search

# implicit-convert.uc - uCalc Transformation file
# This file was saved with uCalc Transform 2.96 on 5/21/2014 5:14:40 PM
# Comment: Handles implicit data type conversions

ExternalKeywords: Exclude, Comment, Selected, ParentChild, FindMode, InputFile, OutputFile, BatchAction, SEND
ExternalKeywords: Highlight, ForeColor, BackColor, FontName, FontSize, FontStyle
ExternalKeywords: FilterEndText, FilterSeparator, FilterSort, FilterSortFunc, FilterStartText, FilterUnique, FilterTally

FindMode: Replace

# Definitions

# Search Criteria

Criteria: 0
Enabled: False
Exclude: False
Comment: Handles implicit data type conversions
Selected: False
Highlight: True
ForeColor: ControlText
BackColor: Aqua
FontName:
FontSize:
FontStyle:
CaseSensitive: False
QuoteSensitive: False
CodeBlockSensitive: False
FilterEndText:
FilterSeparator: {#10}
FilterSort: False
FilterSortFunc:
FilterStartText:
FilterUnique: False
FilterTally: False
Min: 0
Max: -1
MinSoft: 0
MaxSoft: -1
BatchAction: Transform
InputFile:
OutputFile:
SEND:
StartAfter: 0
StopAfter: -1
SkipOver: False
ParentChild: 0
Pass: 0
PassOnce: True
Precedence: 0
RightToLeft: False

Criteria: 1
Enabled: True
Highlight: False
Find:
Replace: {@Eval:
            Dim Size As Table = {
               "Byte", 1, "Word", 2, "Integer", 2, "Long", 4, "Dword", 4,
               "Single", 4, "Double", 8, "Extended", 10
            }
         }
         {@Define:
            Var: Args As String
            SyntaxArgL: {number} = {number:"([0-9]*\.)?[0-9]+(e[-+]?[0-9]+)?"}
         }
         {@Define::
            Token: \x27.* ~~ Properties: ucWhitespace
            Token: _[^\n]*\n ~~ Properties: ucWhitespace
            LineContinue: " _"
         }

Criteria: 2
Comment: Inserts data type names in front of variabls and functions
Pass: 1

Criteria: 3
Enabled: True
Highlight: False
Find: {nl}[Declare]{ Function | Sub } {name:1} [{etc}] ([{args%}]) [ As {ftype:1}]
Replace: {@Define::  Pass: 1 ~~ Syntax: {name}({@Eval:                      _
             Args = Remove("{args}", "{ Optional | ByVal | ByRef | Ptr }"); _
             Replace(Args, "{arg:1} As {type:1}", "{"+"{arg}"+"%}")          _
           }) ::= `{ftype}({name}({@Eval:                                   _
             Args = Remove("{args}", "{ Optional | ByVal | ByRef | Ptr }"); _
             Replace(Args, "{arg:1} As {type:1}", "##{type}({arg})")        _
           }))
         }{Self}

Criteria: 4
Enabled: True
Highlight: False
Find: { Global | Local | Static | Dim | , | { ByVal | ByRef } } {var:1} As {type:1}
Replace: {Self}{@Define:: Pass: 1 ~~ Syntax: {var} ::= `{type}({var})}

Criteria: 5
Enabled: True
Highlight: False
Find: {number}
Replace: `Double({number})

Criteria: 6
Enabled: True
Highlight: False
BackColor: RoyalBlue
Find: {q}{text}{q}
Replace: `StringLit({Self})

Criteria: 7
Enabled: True
Highlight: False
BackColor: Pink
Find: {func: InStr|Len|UBound|VarPtr|StrPtr|Dir|CurDir } ({args%})
Replace: `Long({func}({args}))

Criteria: 8
Enabled: True
Highlight: False
BackColor: SlateBlue
Find: {func: Mid|Left|Right|Remove|Extract|Remain } ({args%})
Replace: `String({func}({args}))

Criteria: 9
Enabled: True
Highlight: False
BackColor: Purple
SkipOver: True
Find: {nl} { Type | Union }
         {members+}
      End {TypeOrUnion}
Replace: [Skip over]

Criteria: 10
Enabled: True
BackColor: Khaki
SkipOver: True
Find: {nl}{ % | $ | # | ! | ASM } {etc} {@Note: Skips equates, metastatements, ASM}
Replace: [Skip over]

Criteria: 11
Comment: Convert
Pass: 2

Criteria: 12
Enabled: True
BackColor: Violet
PassOnce: False
Find: ##Asciiz(string({arg}))
Replace: `Asciiz({arg}.c_str())

Criteria: 13
Enabled: True
PassOnce: False
Find: `StringLit({arg})+`StringLit({arg})
Replace: `String((string){arg}+{arg})

Criteria: 14
Enabled: True
BackColor: CornflowerBlue
PassOnce: False
Find: `WideString({arg}) + `String({arg})
Replace: `WideString({arg}) + `WideString(string({arg}))

Criteria: 15
Enabled: True
BackColor: SandyBrown
PassOnce: False
Find: Len(`String({arg}))
Replace: `Long(({arg}).length())

Criteria: 16
Enabled: True
BackColor: Gold
PassOnce: False
Find: Len(`LPCSTR({arg}))
Replace: `Long(strlen({arg}))

Criteria: 17
Enabled: True
Selected: True
PassOnce: False
Find: `{ Extended | Ext }
Replace: `Double

Criteria: 18
Comment: Highlights the inserted data type names
Pass: 3

Criteria: 19
Enabled: False
BackColor: Red
Find: ##{type:1}
Replace: {Self}

Criteria: 20
Enabled: False
Comment: This line is there to provide highlighting for clarity
Find: `{type:1}
Replace: {Self}

# End Search


another attempt on fixing the isTyping status

class CRZMutator_DmgPlume extends Mutator config (MutatH0r);

// structures sent from server to clients

struct PlumeRepItem
{
  var vector Location;
  var int Value;
};

struct PlumeRepInfo
{
  var PlumeRepItem Plumes[16];
};

// server internal structures to aggregate damage within one tick for each client and victim

struct PlumeVictimInfo
{
  var Pawn Victim;
  var PlumeRepItem RepItem;
};

struct PlumeReceiver
{
  var Controller Controller;
  var DmgPlumeActor Actor;
  var array<PlumeVictimInfo> Victims;
};

// server
var array<PlumeReceiver> PlumeReceivers;

function PostBeginPlay()
{
  super.PostBeginPlay();

  if (Role == ROLE_Authority)
  {
    SetTickGroup(TG_PostAsyncWork);
    Enable('Tick');
  }
}

function InitMutator(string options, out string errorMsg)
{
  super.InitMutator(options, errorMsg);
  MoveMyselfToHeadOfMutatorList();
}

function MoveMyselfToHeadOfMutatorList()
{
  // move this mutator to the start of the mutator list so we don't miss any NetDamage() modifications

  local Mutator mut;

  if (WorldInfo.Game.BaseMutator == self)
    return;
  for (mut = WorldInfo.Game.BaseMutator; mut != None; mut=mut.NextMutator)
  {
    if (mut.NextMutator == self)
    {
      mut.NextMutator = self.NextMutator;
      self.NextMutator = WorldInfo.Game.BaseMutator;
      WorldInfo.Game.BaseMutator = self;
      return;
    }
  }
}

function NetDamage(int OriginalDamage, out int Damage, Pawn Injured, Controller InstigatedBy, Vector HitLocation, out Vector Momentum, class<DamageType> DamageType, Actor DamageCauser)
{
  local int i, j;
  local PlayerController pc;

  super.NetDamage(OriginalDamage, Damage, Injured, InstigatedBy, HitLocation, Momentum, DamageType, DamageCauser);

  pc = PlayerController(InstigatedBy);
  if (pc == none)
    return;

  i = GetOrAddPlumeReceiver(InstigatedBy);

  // find or create plume for victim and aggregate damage
  for (j=0; j<PlumeReceivers[i].Victims.Length; j++)
  {
    if (PlumeReceivers[i].Victims[j].Victim == Injured)
      break;
  }
  if (j>=PlumeReceivers[i].Victims.Length)
  {
    PlumeReceivers[i].Victims.Add(1);
    PlumeReceivers[i].Victims[j].Victim = Injured;
    PlumeReceivers[i].Victims[j].RepItem.Location = Injured.Location + vect(0,0,1)*(Injured.CylinderComponent.CollisionHeight + 3);
  }
  PlumeReceivers[i].Victims[j].RepItem.Value += round(Damage * pc.Pawn.DamageScaling);
}

function Tick(float deltaTime)
{
  local int i, j;
  local PlumeReceiver rec;
  local PlumeRepInfo repInfo;

  if (Role != ROLE_Authority)
    return;

  for (i=0; i<PlumeReceivers.Length; i++)
  {
    rec = PlumeReceivers[i];
    if (rec.Victims.Length == 0)
      continue;

    for (j=0; j<rec.Victims.Length && j<ArrayCount(repInfo.Plumes); j++)
      repInfo.Plumes[j] = rec.Victims[j].RepItem;
    if (j < ArrayCount(repInfo.Plumes)) // mark as end-of-list
      repInfo.Plumes[j].Value = 0;
    rec.Actor.AddPlumes(repInfo);
    PlumeReceivers[i].Victims.Length = 0; // must use full path to set original struct member and not the local copy
  }
}

function int GetOrAddPlumeReceiver(Controller C)
{
  local int i;

  // find or create plume receiver
  for (i=0; i<PlumeReceivers.Length; i++)
  {
    if (PlumeReceivers[i].Controller == C)
      return i;
  }

  PlumeReceivers.Add(1);
  PlumeReceivers[i].Controller = C;
  PlumeReceivers[i].Actor = Spawn(class'DmgPlumeActor', C);
  PlumeReceivers[i].Actor.Mut = self;
  return i;
}

function NotifyLogin(Controller C)
{
  super.NotifyLogin(C);

  if (PlayerController(C) != None)
    GetOrAddPlumeReceiver(C);
}

function NotifyLogout(Controller C)
{
  local int i, j, playerId;

  if (PlayerController(C) != None)
  {
    for (i=0; i<PlumeReceivers.Length; i++)
    {
      if (PlumeReceivers[i].Controller == C)
      {
        // tell all clients that the player isn't typing anymore (he may reconnect later, and should not have a chat bubble)
        if (PlumeReceivers[i].Actor.isTyping)
        {
          playerId = C.PlayerReplicationInfo.PlayerID;
          for (j=0; j<PlumeReceivers.Length; j++)
          {
            if (PlumeReceivers[j].Controller != C)
              PlumeReceivers[j].Actor.NotifyIsTyping(playerId, false);
          }
        }

        PlumeReceivers[i].Actor.Destroy();
        PlumeReceivers.Remove(i, 1);
        break;
      }
    }
  }

  super.NotifyLogout(C);
}

DefaultProperties
{
}

class CRZMutator_DmgPlume extends Mutator config (MutatH0r);

// structures sent from server to clients

struct PlumeRepItem
{
  var vector Location;
  var int Value;
};

struct PlumeRepInfo
{
  var PlumeRepItem Plumes[16];
};

// server internal structures to aggregate damage within one tick for each client and victim

struct PlumeVictimInfo
{
  var Pawn Victim;
  var PlumeRepItem RepItem;
};

struct PlumeReceiver
{
  var Controller Controller;
  var DmgPlumeActor Actor;
  var array<PlumeVictimInfo> Victims;
};

// server
var array<PlumeReceiver> PlumeReceivers;

function PostBeginPlay()
{
  super.PostBeginPlay();

  if (Role == ROLE_Authority)
  {
    SetTickGroup(TG_PostAsyncWork);
    Enable('Tick');
  }
}

function InitMutator(string options, out string errorMsg)
{
  super.InitMutator(options, errorMsg);
  MoveMyselfToHeadOfMutatorList();
}

function MoveMyselfToHeadOfMutatorList()
{
  // move this mutator to the start of the mutator list so we don't miss any NetDamage() modifications

  local Mutator mut;

  if (WorldInfo.Game.BaseMutator == self)
    return;
  for (mut = WorldInfo.Game.BaseMutator; mut != None; mut=mut.NextMutator)
  {
    if (mut.NextMutator == self)
    {
      mut.NextMutator = self.NextMutator;
      self.NextMutator = WorldInfo.Game.BaseMutator;
      WorldInfo.Game.BaseMutator = self;
      return;
    }
  }
}

function NetDamage(int OriginalDamage, out int Damage, Pawn Injured, Controller InstigatedBy, Vector HitLocation, out Vector Momentum, class<DamageType> DamageType, Actor DamageCauser)
{
  local int i, j;
  local PlayerController pc;

  super.NetDamage(OriginalDamage, Damage, Injured, InstigatedBy, HitLocation, Momentum, DamageType, DamageCauser);

  pc = PlayerController(InstigatedBy);
  if (pc == none)
    return;

  i = GetOrAddPlumeReceiver(InstigatedBy);

  // find or create plume for victim and aggregate damage
  for (j=0; j<PlumeReceivers[i].Victims.Length; j++)
  {
    if (PlumeReceivers[i].Victims[j].Victim == Injured)
      break;
  }
  if (j>=PlumeReceivers[i].Victims.Length)
  {
    PlumeReceivers[i].Victims.Add(1);
    PlumeReceivers[i].Victims[j].Victim = Injured;
    PlumeReceivers[i].Victims[j].RepItem.Location = Injured.Location + vect(0,0,1)*(Injured.CylinderComponent.CollisionHeight + 3);
  }
  PlumeReceivers[i].Victims[j].RepItem.Value += round(Damage * pc.Pawn.DamageScaling);
}

function Tick(float deltaTime)
{
  local int i, j;
  local PlumeReceiver rec;
  local PlumeRepInfo repInfo;

  if (Role != ROLE_Authority)
    return;

  for (i=0; i<PlumeReceivers.Length; i++)
  {
    rec = PlumeReceivers[i];
    if (rec.Victims.Length == 0)
      continue;

    for (j=0; j<rec.Victims.Length && j<ArrayCount(repInfo.Plumes); j++)
      repInfo.Plumes[j] = rec.Victims[j].RepItem;
    if (j < ArrayCount(repInfo.Plumes)) // mark as end-of-list
      repInfo.Plumes[j].Value = 0;
    rec.Actor.AddPlumes(repInfo);
    PlumeReceivers[i].Victims.Length = 0; // must use full path to set original struct member and not the local copy
  }
}

function int GetOrAddPlumeReceiver(Controller C)
{
  local int i;

  // find or create plume receiver
  for (i=0; i<PlumeReceivers.Length; i++)
  {
    if (PlumeReceivers[i].Controller == C)
      return i;
  }

  PlumeReceivers.Add(1);
  PlumeReceivers[i].Controller = C;
  PlumeReceivers[i].Actor = Spawn(class'DmgPlumeActor', C);
  PlumeReceivers[i].Actor.Mut = self;
  return i;
}

function NotifyLogin(Controller C)
{
  super.NotifyLogin(C);

  if (PlayerController(C) != None)
    GetOrAddPlumeReceiver(C);
}

function NotifyLogout(Controller C)
{
  local int i;

  if (PlayerController(C) != None)
  {
    for (i=0; i<PlumeReceivers.Length; i++)
    {
      if (PlumeReceivers[i].Controller == C)
      {
        PlumeReceivers[i].Actor.Destroy();
        PlumeReceivers.Remove(i, 1);
        break;
      }
      else if (PlumeReceivers[i].Actor.isTyping) // tell all clients that the player isn't typing anymore (he may reconnect later, so this is important)
        PlumeReceivers[i].Actor.SetTyping(C.PlayerReplicationInfo.PlayerID, false);
    }
  }

  super.NotifyLogout(C);
}

DefaultProperties
{
}


Version 1.1.1 for patch release.

Version 1.1.1 for patch release.

//---------------------------------------------------------------------------------------
//  FILE:    CHXComGameVersionTemplate.uc
//  AUTHOR:  X2CommunityCore
//  PURPOSE: Version information for the Community Highlander XComGame replacement.
//
//  Issue #1
//
//  This is implemented as a template to allow mods to detect whether the Community Highlander
//  is installed. It's a template to avoid needing to compile against any
//  new sources to get mods to build (which would then crash the game if it tried
//  to access a function //  or variable that wasn't installed anyway). Can be queried by:
//
//  1) Query the StrategyElementTemplateManager for a template named 'CHXComGameVersion'. If you get back
//     a non-none result the XcomGame replacement is installed (or someone is lying and added the template without
//     the actual XComGame replacement...)
//  2) If you need more fine-grained info, such as the particular version, then once you get back a non-none
//     result you can cast it to class 'CHXComGameVersionTemplate' to get the version number through the API below.
//
//  Don't directly look up the template and cast it without checking if you got a non-none result or the game will
//  probably crash when the replacement XComGame isn't present.
//
//  Supports major, minor, and build versions, but build is currently unimplemented.
//---------------------------------------------------------------------------------------
class CHXComGameVersionTemplate extends X2StrategyElementTemplate;

var int MajorVersion;
var int MinorVersion;
var int PatchVersion;

// "Short" version number (minus the patch)
function String GetShortVersionString()
{
    return default.MajorVersion $ "." $ default.MinorVersion;
}

// Version number in string format.
function String GetVersionString()
{
    return default.MajorVersion $ "." $ default.MinorVersion $ "." $ default.PatchVersion;
}

// Version number in comparable numeric format. Number in decimal is MMmmmmPPPP where:O
// "M" is major version
// "m" is minor version
// "P" is patch number
//
// Allows for approx. 2 digits of major, 4 digits of minor versions and 9,999 builds before overflowing.
//
// Optional params take individual components of the version
//
// Note: build number currently disabled and is always 0.
function int GetVersionNumber()
{
    return (default.MajorVersion * 100000000) + (default.MinorVersion * 10000) + (default.PatchVersion);
}

defaultproperties
{
    MajorVersion = 1;
    MinorVersion = 1;
    PatchVersion = 1;
}

//---------------------------------------------------------------------------------------
//  FILE:    CHXComGameVersionTemplate.uc
//  AUTHOR:  X2CommunityCore
//  PURPOSE: Version information for the Community Highlander XComGame replacement.
//
//  Issue #1
//
//  This is implemented as a template to allow mods to detect whether the Community Highlander
//  is installed. It's a template to avoid needing to compile against any
//  new sources to get mods to build (which would then crash the game if it tried
//  to access a function //  or variable that wasn't installed anyway). Can be queried by:
//
//  1) Query the StrategyElementTemplateManager for a template named 'CHXComGameVersion'. If you get back
//     a non-none result the XcomGame replacement is installed (or someone is lying and added the template without
//     the actual XComGame replacement...)
//  2) If you need more fine-grained info, such as the particular version, then once you get back a non-none
//     result you can cast it to class 'CHXComGameVersionTemplate' to get the version number through the API below.
//
//  Don't directly look up the template and cast it without checking if you got a non-none result or the game will
//  probably crash when the replacement XComGame isn't present.
//
//  Supports major, minor, and build versions, but build is currently unimplemented.
//---------------------------------------------------------------------------------------
class CHXComGameVersionTemplate extends X2StrategyElementTemplate;

var int MajorVersion;
var int MinorVersion;
var int PatchVersion;

// "Short" version number (minus the patch)
function String GetShortVersionString()
{
    return default.MajorVersion $ "." $ default.MinorVersion;
}

// Version number in string format.
function String GetVersionString()
{
    return default.MajorVersion $ "." $ default.MinorVersion $ "." $ default.PatchVersion;
}

// Version number in comparable numeric format. Number in decimal is MMmmmmPPPP where:O
// "M" is major version
// "m" is minor version
// "P" is patch number
//
// Allows for approx. 2 digits of major, 4 digits of minor versions and 9,999 builds before overflowing.
//
// Optional params take individual components of the version
//
// Note: build number currently disabled and is always 0.
function int GetVersionNumber()
{
    return (default.MajorVersion * 100000000) + (default.MinorVersion * 10000) + (default.PatchVersion);
}

defaultproperties
{
    MajorVersion = 1;
    MinorVersion = 1;
    PatchVersion = 0;
}


Add black market game state for modifications

//---------------------------------------------------------------------------------------
//  FILE:    XComGameState_BlackMarket.uc
//  AUTHOR:  Mark Nauta  --  08/21/2014
//  PURPOSE: This object represents the instance data for the Black Markets on the
//           X-Com 2 strategy game map
//
//---------------------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//---------------------------------------------------------------------------------------
class XComGameState_BlackMarket extends XComGameState_ScanningSite
	config(GameData) dependson(X2StrategyGameRulesetDataStructures) native(Core);

var int									SupplyReserve; // Current number of Supplies the Black Market has
var bool								bNeedsScan; // When the Black Market appears, it needs to be scanned to open
var bool								bIsOpen;
var bool								bForceClosed; // Dark Event: Gone to Ground
var bool								bLandedUFOMission; // Replace the supply raid mission with landed UFO for this month
var bool								bPurchasedUFOMission; // Has the player purchased the current UFO mission
var bool								bPurchasedSupplyMission; // Has the player purchased the current supply raid mission
var bool								bNeedsAppearedPopup; // Should the POI Appeared popup be displayed for the Market
var bool								bNeedsOpenPopup;  // Should the Black Market window popup be displayed
var bool								bHasSeenNewGoods; // Has the player seen new goods the Black Market is offering
var TDateTime							OpeningTime; // we've got the best deals anywhere
var TDateTime							ClosingTime;  // you don't have to go home, but you can't stay here
var array<Commodity>					ForSaleItems;
var deprecated array<StateObjectReference>			Interests;
var array<name>							InterestTemplates;
var array<BlackMarketItemPrice>			BuyPrices; // Prices for items in your inventory
var StateObjectReference				Mission;
var int									NumTimesAppeared;

// Modifiers
var float								PriceReductionScalar; // Alien Cypher Dark Event does not effect BM so apply inverse scalar here
var int									GoodsCostPercentDiscount; // QuidProQuo Continent Bonus
var int									BuyPricePercentIncrease; // UnderTheTable Continent Bonus

var config array<int>					MinDaysToShow;
var config array<int>					MaxDaysToShow;
var config array<int>					NumInterestItems;
var config array<int>					NumTechRushes;
var config array<int>					TechPointsPerIntelCost;
var config array<int>					BaseItemIntelCost;
var config array<int>					PersonnelItemIntelCost;
var config array<int>					IntelCostVariance;
var config array<int>					ItemIntelCostIncrease;
var config array<int>					PersonnelItemIntelCostIncrease;
var config array<int>					BuyPriceVariancePercent;
var config array<int>					InterestPriceMultiplier;
var config array<float>					WeaponUpgradeCostScalar;
var config array<float>					SupplyGoodScalar;
var config array<StrategyCostScalar>	GoodsCostScalars;

var config int							ChosenInfoChanceIncrease;
var config int							MaxChosenInfoChance;

cpptext
{
public:
	virtual void PostLoad();
}
//#############################################################################################
//----------------   INITIALIZATION   ---------------------------------------------------------
//#############################################################################################

//---------------------------------------------------------------------------------------
static function SetUpBlackMarket(XComGameState StartState)
{
	local XComGameState_BlackMarket BlackMarketState;
	local int HoursToAdd;

	BlackMarketState = XComGameState_BlackMarket(StartState.CreateNewStateObject(class'XComGameState_BlackMarket'));

	// Set the time when the Black Market will open
	HoursToAdd = (`ScaleStrategyArrayInt(default.MinDaysToShow) * 24) + `SYNC_RAND_STATIC((`ScaleStrategyArrayInt(default.MaxDaysToShow) * 24) - (`ScaleStrategyArrayInt(default.MinDaysToShow) * 24) + 1);
	BlackMarketState.OpeningTime = GetCurrentTime();
	class'X2StrategyGameRulesetDataStructures'.static.AddHours(BlackMarketState.OpeningTime, HoursToAdd);
}

//#############################################################################################
//----------------   OPENING/CLOSING   --------------------------------------------------------
//#############################################################################################

//---------------------------------------------------------------------------------------
function bool ShowBlackMarket(XComGameState NewGameState, optional bool bForceShow = false)
{
	if (bForceShow || (!bIsOpen && !bForceClosed && !bNeedsScan && class'X2StrategyGameRulesetDataStructures'.static.LessThan(OpeningTime, GetCurrentTime())))
	{
		bNeedsScan = true;
		bNeedsAppearedPopup = true;
		SetScanHoursRemaining(`ScaleStrategyArrayInt(default.MinScanDays), `ScaleStrategyArrayInt(default.MaxScanDays));

		SetContinent();

		ResetBlackMarketGoods(NewGameState);

		return true;
	}

	return false;
}

//---------------------------------------------------------------------------------------
function OpenBlackMarket(XComGameState NewGameState)
{
	bNeedsScan = false;
	bIsOpen = true;
	bForceClosed = false;
	bNeedsOpenPopup = true;
}

//---------------------------------------------------------------------------------------
function ForceCloseBlackMarket(XComGameState NewGameState)
{
	bNeedsScan = false;
	bIsOpen = false;
	bForceClosed = true;
	ResetScan();
}

//---------------------------------------------------------------------------------------
function ResetBlackMarketGoods(XComGameState NewGameState)
{
	NumTimesAppeared++;
	CleanUpForSaleItems(NewGameState);
	BuyPrices.Length = 0;
	SetInterests();
	SetUpForSaleItems(NewGameState);
	UpdateBuyPrices();

	bHasSeenNewGoods = false;
}

//---------------------------------------------------------------------------------------
function SetContinent()
{
	local XComGameStateHistory History;
	local XComGameState_WorldRegion RegionState;
	local array<XComGameState_WorldRegion> AllRegions, ValidRegions;

	History = `XCOMHISTORY;

	foreach History.IterateByClassType(class'XComGameState_WorldRegion', RegionState)
	{
		AllRegions.AddItem(RegionState);

		if(RegionState.HaveMadeContact())
		{
			ValidRegions.AddItem(RegionState);
		}
	}

	if(ValidRegions.Length > 0)
	{
		RegionState = ValidRegions[`SYNC_RAND(ValidRegions.Length)];
	}
	else
	{
		RegionState = AllRegions[`SYNC_RAND(AllRegions.Length)];
	}

	Continent = RegionState.GetContinent().GetReference();
	SetLocation(RegionState.GetContinent());
}

//---------------------------------------------------------------------------------------
function SetLocation(XComGameState_Continent ContinentState)
{
	Location = ContinentState.GetRandomLocationInContinent(, self);
}

//---------------------------------------------------------------------------------------
function SetUpForSaleItems(XComGameState NewGameState)
{
	local X2StrategyElementTemplateManager StratMgr;
	local XComGameState_Reward RewardState;
	local X2RewardTemplate RewardTemplate;
	local Commodity ForSaleItem, EmptyForSaleItem;
	local array<XComGameState_Item> ItemList;
	local array<XComGameState_Tech> TechList;
	local array<name> PersonnelRewardNames;
	local int idx;

	StratMgr = class'X2StrategyElementTemplateManager'.static.GetStrategyElementTemplateManager();
	RewardTemplate = X2RewardTemplate(StratMgr.FindStrategyElementTemplate('Reward_Item'));
	ItemList = RollForBlackMarketLoot(NewGameState);

	// Loot Table Rewards
	for(idx = 0; idx < ItemList.Length; idx++)
	{
		ForSaleItem = EmptyForSaleItem;
		RewardState = RewardTemplate.CreateInstanceFromTemplate(NewGameState);
		RewardState.SetReward(ItemList[idx].GetReference());
		ForSaleItem.RewardRef = RewardState.GetReference();

		ForSaleItem.Title = RewardState.GetRewardString();

		if(X2WeaponUpgradeTemplate(ItemList[idx].GetMyTemplate()) != none)
		{
			ForSaleItem.Cost = GetForSaleItemCost(`ScaleStrategyArrayFloat(default.WeaponUpgradeCostScalar) * PriceReductionScalar);
		}
		else
		{
			ForSaleItem.Cost = GetForSaleItemCost(PriceReductionScalar);
		}

		ForSaleItem.Desc = RewardState.GetBlackMarketString();
		ForSaleItem.Image = RewardState.GetRewardImage();
		ForSaleItem.CostScalars = GoodsCostScalars;
		ForSaleItem.DiscountPercent = GoodsCostPercentDiscount;

		ForSaleItems.AddItem(ForSaleItem);
	}

	RewardTemplate = X2RewardTemplate(StratMgr.FindStrategyElementTemplate('Reward_TechRush'));
	TechList = RollForTechRushItems();

	// Tech Rush Rewards
	for(idx = 0; idx < TechList.Length; idx++)
	{
		ForSaleItem = EmptyForSaleItem;
		RewardState = RewardTemplate.CreateInstanceFromTemplate(NewGameState);
		RewardState.SetReward(TechList[idx].GetReference());
		ForSaleItem.RewardRef = RewardState.GetReference();

		ForSaleItem.Title = RewardState.GetRewardString();
		ForSaleItem.Cost = GetTechRushCost(TechList[idx], NewGameState, PriceReductionScalar);
		ForSaleItem.Desc = RewardState.GetBlackMarketString();
		ForSaleItem.Image = RewardState.GetRewardImage();
		ForSaleItem.CostScalars = GoodsCostScalars;
		ForSaleItem.DiscountPercent = GoodsCostPercentDiscount;

		ForSaleItems.AddItem(ForSaleItem);
	}

	// Supply Reward
	ForSaleItem = EmptyForSaleItem;
	RewardTemplate = X2RewardTemplate(StratMgr.FindStrategyElementTemplate('Reward_Supplies'));
	RewardState = RewardTemplate.CreateInstanceFromTemplate(NewGameState);
	RewardState.GenerateReward(NewGameState, `ScaleStrategyArrayFloat(default.SupplyGoodScalar));
	ForSaleItem.RewardRef = RewardState.GetReference();

	ForSaleItem.Title = RewardState.GetRewardString();
	ForSaleItem.Cost = GetForSaleItemCost(PriceReductionScalar);
	ForSaleItem.Desc = RewardState.GetBlackMarketString();
	ForSaleItem.Image = RewardState.GetRewardImage();
	ForSaleItem.CostScalars = GoodsCostScalars;
	ForSaleItem.DiscountPercent = GoodsCostPercentDiscount;

	ForSaleItems.AddItem(ForSaleItem);

	// Personnel Reward
	PersonnelRewardNames.AddItem('Reward_Scientist');
	PersonnelRewardNames.AddItem('Reward_Engineer');
	PersonnelRewardNames.AddItem('Reward_Soldier');

	ForSaleItem = EmptyForSaleItem;
	RewardTemplate = X2RewardTemplate(StratMgr.FindStrategyElementTemplate(PersonnelRewardNames[`SYNC_RAND(PersonnelRewardNames.Length)]));

	// Only give the personnel reward if it is available for the player
	if (RewardTemplate.IsRewardAvailableFn == none || RewardTemplate.IsRewardAvailableFn(NewGameState))
	{
		RewardState = RewardTemplate.CreateInstanceFromTemplate(NewGameState);

		RewardState.GenerateReward(NewGameState, , Region);
		ForSaleItem.RewardRef = RewardState.GetReference();

		ForSaleItem.Title = RewardState.GetRewardString();
		ForSaleItem.Cost = GetPersonnelForSaleItemCost(PriceReductionScalar);
		ForSaleItem.Desc = RewardState.GetBlackMarketString();
		ForSaleItem.Image = RewardState.GetRewardImage();
		ForSaleItem.CostScalars = GoodsCostScalars;
		ForSaleItem.DiscountPercent = GoodsCostPercentDiscount;

		if (ForSaleItem.Image == "")
		{
			`HQPRES.GetPhotoboothAutoGen().AddHeadShotRequest(RewardState.RewardObjectReference, 512, 512, OnUnitHeadCaptureFinished);
			`HQPRES.GetPhotoboothAutoGen().RequestPhotos();
		}

		ForSaleItems.AddItem(ForSaleItem);
	}

	// Chosen Information
	ForSaleItem = EmptyForSaleItem;
	RewardTemplate = X2RewardTemplate(StratMgr.FindStrategyElementTemplate('Reward_ChosenInformation'));

	if(SellChosenInfo() && (RewardTemplate.IsRewardAvailableFn == none || RewardTemplate.IsRewardAvailableFn(NewGameState)))
	{
		RewardState = RewardTemplate.CreateInstanceFromTemplate(NewGameState);

		RewardState.GenerateReward(NewGameState);
		ForSaleItem.RewardRef = RewardState.GetReference();

		ForSaleItem.Title = RewardState.GetRewardString();
		ForSaleItem.Cost = GetForSaleItemCost(PriceReductionScalar);
		ForSaleItem.Desc = RewardState.GetBlackMarketString();
		ForSaleItem.Image = RewardState.GetRewardImage();
		ForSaleItem.CostScalars = GoodsCostScalars;
		ForSaleItem.DiscountPercent = GoodsCostPercentDiscount;
		ForSaleItems.AddItem(ForSaleItem);
	}
}

private function bool SellChosenInfo()
{
	local int RollAmount;

	RollAmount = Clamp((NumTimesAppeared * default.ChosenInfoChanceIncrease), 0, default.MaxChosenInfoChance);
	return class'X2StrategyGameRulesetDataStructures'.static.Roll(RollAmount);
}

private function OnUnitHeadCaptureFinished(StateObjectReference UnitRef)
{
}

//---------------------------------------------------------------------------------------
function array<XComGameState_Tech> RollForTechRushItems()
{
	local XComGameStateHistory History;
	local XComGameState_HeadquartersXCom XComHQ;
	local array<XComGameState_Tech> ChosenTechs;
	local XComGameState_Tech TechState;
	local array<StateObjectReference> AvailableTechRefs;
	local int idx;

	History = `XCOMHISTORY;
	XComHQ = XComGameState_HeadquartersXCom(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));

	// Grab all available techs
	AvailableTechRefs = XComHQ.GetAvailableTechsForResearch();

	// Include current Tech being researched
	TechState = XComHQ.GetCurrentResearchTech();

	if(TechState != none)
	{
		AvailableTechRefs.AddItem(TechState.GetReference());
	}

	// Filter Techs (no instant, repeatable, priority)
	for(idx = 0; idx < AvailableTechRefs.Length; idx++)
	{
		TechState = XComGameState_Tech(History.GetGameStateForObjectID(AvailableTechRefs[idx].ObjectID));

		if(TechState != none && TechState.CanBeRushed())
		{
			ChosenTechs.AddItem(TechState);
		}
	}

	// Limit chosen techs to a max number
	while (ChosenTechs.Length > `ScaleStrategyArrayInt(default.NumTechRushes))
	{
		ChosenTechs.Remove(`SYNC_RAND_STATIC(ChosenTechs.Length), 1);
	}

	return ChosenTechs;
}

//---------------------------------------------------------------------------------------
function array<XComGameState_Item> RollForBlackMarketLoot(XComGameState NewGameState)
{
	local X2ItemTemplateManager ItemMgr;
	local array<XComGameState_Item> ItemList;
	local XComGameState_Item ItemState;
	local X2ItemTemplate ItemTemplate;
	local X2LootTableManager LootManager;
	local LootResults Loot;
	local int LootIndex, idx, i;
	local bool bFound;

	ItemMgr = class'X2ItemTemplateManager'.static.GetItemTemplateManager();
	LootManager = class'X2LootTableManager'.static.GetLootTableManager();
	LootIndex = LootManager.FindGlobalLootCarrier('BlackMarket');

	if(LootIndex >= 0)
	{
		LootManager.RollForGlobalLootCarrier(LootIndex, Loot);
	}

	for(idx = 0; idx < Loot.LootToBeCreated.Length; idx++)
	{
		bFound = false;

		if(InterestTemplates.Find(Loot.LootToBeCreated[idx]) == INDEX_NONE)
		{
			for(i = 0; i < ItemList.Length; i++)
			{
				if(Loot.LootToBeCreated[idx] == ItemList[i].GetMyTemplateName())
				{
					bFound = true;
					ItemList[i].Quantity++;
					break;
				}
			}

			if(!bFound)
			{
				ItemTemplate = ItemMgr.FindItemTemplate(Loot.LootToBeCreated[idx]);

				if(ItemTemplate != none)
				{
					ItemState = ItemTemplate.CreateInstanceFromTemplate(NewGameState);
					ItemList.AddItem(ItemState);
				}
			}
		}
	}

	return ItemList;
}

//---------------------------------------------------------------------------------------
function SetInterests()
{
	local XComGameStateHistory History;
	local XComGameState_HeadquartersXCom XComHQ;
	local XComGameState_Item ItemState;
	local array<StateObjectReference> AllItems;
	local name InterestName;
	local int idx, i;

	History = `XCOMHISTORY;
	XComHQ = XComGameState_HeadquartersXCom(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));
	AllItems = XComHQ.GetTradingPostItems();
	InterestTemplates.Length = 0;

	for(idx = 0; idx < `ScaleStrategyArrayInt(default.NumInterestItems); idx++)
	{
		if(AllItems.Length > 0)
		{
			ItemState = XComGameState_Item(History.GetGameStateForObjectID(AllItems[`SYNC_RAND(AllItems.Length)].ObjectID));

			if(ItemState != none)
			{
				InterestName = ItemState.GetMyTemplateName();
				InterestTemplates.AddItem(InterestName);

				for(i = 0; i < AllItems.Length; i++)
				{
					ItemState = XComGameState_Item(History.GetGameStateForObjectID(AllItems[i].ObjectID));

					if(ItemState != none && ItemState.GetMyTemplateName() == InterestName)
					{
						AllItems.Remove(i, 1);
						i--;
					}
				}
			}
		}
	}
}

//---------------------------------------------------------------------------------------
function UpdateForSaleItemDiscount()
{
	local int idx;

	for (idx = 0; idx < ForSaleItems.Length; idx++)
	{
		ForSaleItems[idx].DiscountPercent = GoodsCostPercentDiscount;
	}
}

//---------------------------------------------------------------------------------------
function bool UpdateBuyPrices()
{
	local XComGameStateHistory History;
	local XComGameState_HeadquartersXCom XComHQ;
	local array<StateObjectReference> AllItems;
	local bool bUpdated;
	local int idx;
	local BlackMarketItemPrice BuyPrice;

	History = `XCOMHISTORY;
	XComHQ = XComGameState_HeadquartersXCom(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));
	AllItems = XComHQ.GetTradingPostItems();
	bUpdated = false;

	// Remove prices for items not available to be sold
	for(idx = 0; idx < BuyPrices.Length; idx++)
	{
		if(AllItems.Find('ObjectID', BuyPrices[idx].ItemRef.ObjectID) == INDEX_NONE)
		{
			BuyPrices.Remove(idx, 1);
			idx--;
			bUpdated = true;
		}
	}

	// Add items that aren't in the price list
	for(idx = 0; idx < AllItems.Length; idx++)
	{
		if(BuyPrices.Find('ItemRef', AllItems[idx]) == INDEX_NONE)
		{
			BuyPrice = GetItemPrice(AllItems[idx]);
			BuyPrices.AddItem(BuyPrice);
			bUpdated = true;
		}
	}

	return bUpdated;
}

//---------------------------------------------------------------------------------------
function private BlackMarketItemPrice GetItemPrice(StateObjectReference ItemRef)
{
	local XComGameStateHistory History;
	local XComGameState_Item ItemState;
	local BlackMarketItemPrice BuyPrice;
	local int PriceDelta;

	History = `XCOMHISTORY;
	ItemState = XComGameState_Item(History.GetGameStateForObjectID(ItemRef.ObjectID));
	BuyPrice.ItemRef = ItemRef;
	BuyPrice.Price = ItemState.GetMyTemplate().TradingPostValue;
	PriceDelta = float(BuyPrice.Price) * (float(`SYNC_RAND(`ScaleStrategyArrayInt(default.BuyPriceVariancePercent))) / 100.0);

	if(class'X2StrategyGameRulesetDataStructures'.static.Roll(50))
	{
		PriceDelta = -PriceDelta;
	}

	BuyPrice.Price += PriceDelta;

	if(BuyPrice.Price <= 0)
	{
		BuyPrice.Price = 1;
	}

	if(InterestTemplates.Find(ItemState.GetMyTemplateName()) != INDEX_NONE)
	{
		BuyPrice.Price *= `ScaleStrategyArrayInt(default.InterestPriceMultiplier);
	}

	return BuyPrice;
}

//---------------------------------------------------------------------------------------
function CleanUpForSaleItems(XComGameState NewGameState)
{
	local XComGameState_Reward RewardState;
	local XComGameStateHistory History;
	local int idx;
	local bool bStartState;

	bStartState = (NewGameState.GetContext().IsStartState());
	History = `XCOMHISTORY;

	for(idx = 0; idx < ForSaleItems.Length; idx++)
	{
		if(bStartState)
		{
			RewardState = XComGameState_Reward(NewGameState.GetGameStateForObjectID(ForSaleItems[idx].RewardRef.ObjectID));
		}
		else
		{
			RewardState = XComGameState_Reward(History.GetGameStateForObjectID(ForSaleItems[idx].RewardRef.ObjectID));
		}

		if(RewardState != none)
		{
			RewardState.CleanUpReward(NewGameState);
		}
	}

	ForSaleItems.Length = 0;
}

//#############################################################################################
//----------------   UPDATE   -----------------------------------------------------------------
//#############################################################################################

// THIS FUNCTION SHOULD RETURN TRUE IN ALL THE SAME CASES AS Update
function bool ShouldUpdate( )
{
	local UIStrategyMap StrategyMap;

	StrategyMap = `HQPRES.StrategyMap2D;

	// Do not trigger anything while the Avenger or Skyranger are flying, or if another popup is already being presented
	if (StrategyMap != none && StrategyMap.m_eUIState != eSMS_Flight && !`HQPRES.ScreenStack.IsCurrentClass( class'UIAlert' ))
	{
		// Check if making contact is complete
		if (bNeedsScan && IsScanComplete( ))
		{
			return true;
		}
	}

	return false;
}

//---------------------------------------------------------------------------------------
// IF ADDING NEW CASES WHERE bModified = true, UPDATE FUNCTION ShouldUpdate ABOVE
function bool Update(XComGameState NewGameState)
{
	local UIStrategyMap StrategyMap;
	local bool bModified;

	StrategyMap = `HQPRES.StrategyMap2D;
	bModified = false;

	// Do not trigger anything while the Avenger or Skyranger are flying, or if another popup is already being presented
	if (StrategyMap != none && StrategyMap.m_eUIState != eSMS_Flight && !`HQPRES.ScreenStack.IsCurrentClass(class'UIAlert'))
	{
		// Check if making contact is complete
		if (bNeedsScan && IsScanComplete())
		{
			OpenBlackMarket(NewGameState);
			bModified = true;
		}
	}

	return bModified;
}

//#############################################################################################
//----------------   MISSIONS   ---------------------------------------------------------------
//#############################################################################################

//---------------------------------------------------------------------------------------
function StrategyCost GetForSaleItemCost(optional float CostScalar = 1.0f)
{
	local StrategyCost Cost;
	local ArtifactCost ResourceCost;
	local int IntelAmount, IntelVariance;

	IntelAmount = `ScaleStrategyArrayInt(default.BaseItemIntelCost) + ((NumTimesAppeared - 1) * `ScaleStrategyArrayInt(default.ItemIntelCostIncrease));
	IntelVariance = Round((float(`SYNC_RAND(`ScaleStrategyArrayInt(default.IntelCostVariance))) / 100.0)* float(IntelAmount));

	if(class'X2StrategyGameRulesetDataStructures'.static.Roll(50))
	{
		IntelVariance = -IntelVariance;
	}

	IntelAmount += IntelVariance;
	IntelAmount = Round(float(IntelAmount) * CostScalar);

	// Make it a multiple of 5
	IntelAmount = Round(float(IntelAmount) / 5.0) * 5;

	ResourceCost.ItemTemplateName = 'Intel';
	ResourceCost.Quantity = IntelAmount;
	Cost.ResourceCosts.AddItem(ResourceCost);

	return Cost;
}

//---------------------------------------------------------------------------------------
function StrategyCost GetPersonnelForSaleItemCost(optional float CostScalar = 1.0f)
{
	local StrategyCost Cost;
	local ArtifactCost ResourceCost;
	local int IntelAmount, IntelVariance;

	IntelAmount = `ScaleStrategyArrayInt(default.PersonnelItemIntelCost) + ((NumTimesAppeared - 1) * `ScaleStrategyArrayInt(default.PersonnelItemIntelCostIncrease));
	IntelVariance = Round((float(`SYNC_RAND(`ScaleStrategyArrayInt(default.IntelCostVariance))) / 100.0)* float(IntelAmount));

	if(class'X2StrategyGameRulesetDataStructures'.static.Roll(50))
	{
		IntelVariance = -IntelVariance;
	}

	IntelAmount += IntelVariance;
	IntelAmount = Round(float(IntelAmount) * CostScalar);

	// Make it a multiple of 5
	IntelAmount = Round(float(IntelAmount) / 5.0) * 5;

	ResourceCost.ItemTemplateName = 'Intel';
	ResourceCost.Quantity = IntelAmount;
	Cost.ResourceCosts.AddItem(ResourceCost);

	return Cost;
}

function UpdateTechRushItems(XComGameState NewGameState)
{
	local XComGameStateHistory History;
	local XComGameState_Reward RewardState;
	local array<Commodity> UpdatedTechRushes;
	local Commodity TechRushCommodity;
	local int idx;
	local XComGameState_HeadquartersXCom XComHQ;
	local XComGameState_Tech TechState;

	History = `XCOMHISTORY;
	XComHQ = XComGameState_HeadquartersXCom(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));

	for(idx = 0; idx < ForSaleItems.Length; idx++)
	{
		RewardState = XComGameState_Reward(History.GetGameStateForObjectID(ForSaleItems[idx].RewardRef.ObjectID));

		if(RewardState != none && RewardState.GetMyTemplateName() == 'Reward_TechRush')
		{
			TechRushCommodity = ForSaleItems[idx];
			ForSaleItems.Remove(idx, 1);
			idx--;

			if(!XComHQ.TechIsResearched(RewardState.RewardObjectReference))
			{
				TechState = XComGameState_Tech(History.GetGameStateForObjectID(RewardState.RewardObjectReference.ObjectID));
				if (TechState.CanBeRushed()) // Verify the tech can still be rushed before re-adding
				{
					TechRushCommodity.Cost = GetTechRushCost(TechState, NewGameState, PriceReductionScalar);
					UpdatedTechRushes.AddItem(TechRushCommodity);
				}
			}
		}
	}

	for(idx = 0; idx < UpdatedTechRushes.Length; idx++)
	{
		ForSaleItems.AddItem(UpdatedTechRushes[idx]);
	}
}

//---------------------------------------------------------------------------------------
function StrategyCost GetTechRushCost(XComGameState_Tech TechState, XComGameState NewGameState, optional float CostScalar = 1.0f)
{
	local XComGameStateHistory History;
	local XComGameState_HeadquartersProjectResearch ResearchState;
	local int PointsToComplete, IntelCost;
	local StrategyCost StratCost;
	local ArtifactCost ResourceCost;

	History = `XCOMHISTORY;

	foreach History.IterateByClassType(class'XComGameState_HeadquartersProjectResearch', ResearchState)
	{
		if(ResearchState.ProjectFocus == TechState.GetReference())
		{
			ResearchState = XComGameState_HeadquartersProjectResearch(NewGameState.ModifyStateObject(class'XComGameState_HeadquartersProjectResearch', ResearchState.ObjectID));
			ResearchState.UpdateProjectPointsRemaining(ResearchState.GetCurrentWorkPerHour());
			PointsToComplete = ResearchState.ProjectPointsRemaining;
			NewGameState.PurgeGameStateForObjectID(ResearchState.ObjectID);
			break;
		}
	}

	if(PointsToComplete == 0)
	{
		PointsToComplete = TechState.GetMyTemplate().GetPointsToComplete();
	}

	IntelCost = Round((float(PointsToComplete) / float(`ScaleStrategyArrayInt(default.TechPointsPerIntelCost))));
	IntelCost = Round(float(IntelCost) * CostScalar);

	// Make it a multiple of 5
	IntelCost = Round(float(IntelCost) / 5.0) * 5;
	IntelCost = Clamp(IntelCost, 5, IntelCost);
	ResourceCost.ItemTemplateName = 'Intel';
	ResourceCost.Quantity = IntelCost;
	StratCost.ResourceCosts.AddItem(ResourceCost);

	return StratCost;
}

//---------------------------------------------------------------------------------------
function UpdateHuntChosenItems(XComGameState NewGameState)
{
	local XComGameStateHistory History;
	local XComGameState_Reward RewardState;
	local int idx;

	History = `XCOMHISTORY;

	for (idx = 0; idx < ForSaleItems.Length; idx++)
	{
		RewardState = XComGameState_Reward(History.GetGameStateForObjectID(ForSaleItems[idx].RewardRef.ObjectID));

		if (RewardState != none && RewardState.GetMyTemplateName() == 'Reward_ChosenInformation')
		{
			// If the Chosen reward is no longer available because the player located the Stronghold, remove the reward
			if (!RewardState.GetMyTemplate().IsRewardAvailableFn(NewGameState))
			{
				ForSaleItems.Remove(idx, 1);
				idx--;
			}
		}
	}
}

//---------------------------------------------------------------------------------------
function ShowMission(XComGameState NewGameState)
{
	local XComGameState_MissionSite MissionState;

	// Set the mission to be visible and start expiring
	MissionState = XComGameState_MissionSite(NewGameState.ModifyStateObject(class'XComGameState_MissionSite', Mission.ObjectID));
	MissionState.Available = true;
	MissionState.Expiring = true;
	MissionState.TimerStartDateTime = `STRATEGYRULES.GameTime;
	MissionState.SetProjectedExpirationDateTime(MissionState.TimerStartDateTime);
}

//#############################################################################################
//----------------  TRADING POST   ------------------------------------------------------------
//#############################################################################################

//---------------------------------------------------------------------------------------
function array<XComGameState_Item> GetInterests()
{
	local XComGameStateHistory History;
	local XComGameState_HeadquartersXCom XComHQ;
	local array<XComGameState_Item> InterestItems;
	local array<StateObjectReference> AllItems;
	local XComGameState_Item ItemState;
	local int idx;

	History = `XCOMHISTORY;
	XComHQ = XComGameState_HeadquartersXCom(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));
	AllItems = XComHQ.GetTradingPostItems();

	for(idx = 0; idx < AllItems.Length; idx++)
	{
		ItemState = XComGameState_Item(History.GetGameStateForObjectID(AllItems[idx].ObjectID));

		if(ItemState != none && InterestTemplates.Find(ItemState.GetMyTemplateName()) != INDEX_NONE)
		{
			InterestItems.AddItem(ItemState);
		}
	}

	return InterestItems;
}

//---------------------------------------------------------------------------------------
function array<Commodity> GetForSaleList()
{
	return ForSaleItems;
}

//---------------------------------------------------------------------------------------
function BuyBlackMarketItem(StateObjectReference RewardRef)
{
	local XComGameStateHistory History;
	local XComGameState NewGameState;
	local XComGameState_BlackMarket BlackMarketState;
	local XComGameState_HeadquartersXCom XComHQ;
	local XComGameState_Reward RewardState;
	local int ItemIndex;

	History = `XCOMHISTORY;
	XComHQ = XComGameState_HeadquartersXCom(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));
	ItemIndex = ForSaleItems.Find('RewardRef', RewardRef);

	if(ItemIndex != INDEX_NONE)
	{
		RewardState = XComGameState_Reward( History.GetGameStateForObjectID( RewardRef.ObjectID ) );

		NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("Buy Black Market Item");
		XComHQ = XComGameState_HeadquartersXCom(NewGameState.ModifyStateObject(class'XComGameState_HeadquartersXCom', XComHQ.ObjectID));
		XComHQ.BuyCommodity(NewGameState, ForSaleItems[ItemIndex]);
		BlackMarketState = XComGameState_BlackMarket(NewGameState.ModifyStateObject(class'XComGameState_BlackMarket', self.ObjectID));
		BlackMarketState.ForSaleItems.Remove(ItemIndex, 1);

		`XEVENTMGR.TriggerEvent( 'BlackMarketPurchase', RewardState, self, NewGameState );

		`XCOMGAME.GameRuleset.SubmitGameState(NewGameState);

		// Display any popups associated with the reward we just purchased
		RewardState.DisplayRewardPopup();
	}
}

//#############################################################################################
//----------------   Geoscape Entity Implementation   -----------------------------------------
//#############################################################################################

function string GetDisplayName()
{
	return m_strDisplayLabel;
}

function bool HasTooltipBounds()
{
	return ShouldBeVisible();
}

function bool CanBeScanned()
{
	return bNeedsScan;
}

protected function bool CanInteract()
{
	return ShouldBeVisible();
}

function bool ShouldBeVisible()
{
	return bNeedsScan || bIsOpen;
}

function class<UIStrategyMapItem> GetUIClass()
{
	return class'UIStrategyMapItem_BlackMarket';
}

// The static mesh for this entities 3D UI
function StaticMesh GetStaticMesh()
{
	return StaticMesh'UI_3D.Overwold_Final.BlackMarkets';
}

// Scale adjustment for the 3D UI static mesh
function vector GetMeshScale()
{
	local vector ScaleVector;

	ScaleVector.X = 1;
	ScaleVector.Y = 1;
	ScaleVector.Z = 1;

	return ScaleVector;
}

function OnXComEnterSite()
{
	local XComGameState NewGameState;

	super.OnXComEnterSite();

	NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("Trigger Event: Avenger Landed POI");
	`XEVENTMGR.TriggerEvent('AvengerLandedScanPOI', , , NewGameState);
	`GAMERULES.SubmitGameState(NewGameState);
}

protected function bool DisplaySelectionPrompt()
{
	local XComGameState_HeadquartersXCom XComHQ;

	XComHQ = class'UIUtilities_Strategy'.static.GetXComHQ();

	// if click here and XComHQ is not in the region, fly to it
	if (XComHQ.CurrentLocation != GetReference())
	{
		return false;
	}

	return true;
}

function DisplayBlackMarket()
{
	if (bIsOpen)
	{
		SetNewGoodsSeen();
		`HQPRES.UIBlackMarket();
	}
}

function UpdateGameBoard()
{
	local XComGameState NewGameState;
	local XComGameState_BlackMarket BlackMarketState;
	local bool bSuccess;

	if (ShouldUpdate())
	{
		NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState( "Update Black Market" );

		BlackMarketState = XComGameState_BlackMarket( NewGameState.ModifyStateObject( class'XComGameState_BlackMarket', ObjectID ) );

		bSuccess = BlackMarketState.Update(NewGameState);
		`assert( bSuccess );

		`XCOMGAME.GameRuleset.SubmitGameState( NewGameState );
	}

	if (bNeedsAppearedPopup)
	{
		BlackMarketAppearedPopup();
	}
	else if (bNeedsOpenPopup)
	{
		BlackMarketPopup();
	}
}

//---------------------------------------------------------------------------------------
function DestinationReached()
{
	super.DestinationReached();

	if (bIsOpen)
	{
		SetNewGoodsSeen();
		`HQPRES.UIBlackMarket();
	}
}

//---------------------------------------------------------------------------------------
function SetNewGoodsSeen()
{
	local XComGameState NewGameState;
	local XComGameState_BlackMarket BlackMarketState;

	if (!bHasSeenNewGoods)
	{
		// Flag the black market goods as having been seen
		NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("New black market goods seen");
		BlackMarketState = XComGameState_BlackMarket(NewGameState.ModifyStateObject(class'XComGameState_BlackMarket', ObjectID));
		BlackMarketState.bHasSeenNewGoods = true;
		`XCOMGAME.GameRuleset.SubmitGameState(NewGameState);
	}
}

//---------------------------------------------------------------------------------------
simulated public function BlackMarketAppearedPopup()
{
	local XComGameState NewGameState;
	local XComGameState_BlackMarket BlackMarketState;

	NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("Toggle Black Market Appeared Popup");
	BlackMarketState = XComGameState_BlackMarket(NewGameState.ModifyStateObject(class'XComGameState_BlackMarket', self.ObjectID));
	BlackMarketState.bNeedsAppearedPopup = false;
	`XCOMGAME.GameRuleset.SubmitGameState(NewGameState);

	`HQPRES.UIBlackMarketAppearedAlert();

	`GAME.GetGeoscape().Pause();
}

//---------------------------------------------------------------------------------------
simulated public function BlackMarketPopup()
{
	local XComGameState NewGameState;
	local XComGameState_BlackMarket BlackMarketState;

	NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("Toggle Black Market Open Popup");
	BlackMarketState = XComGameState_BlackMarket(NewGameState.ModifyStateObject(class'XComGameState_BlackMarket', self.ObjectID));
	BlackMarketState.bNeedsOpenPopup = false;
	`XCOMGAME.GameRuleset.SubmitGameState(NewGameState);

	if (NumTimesAppeared > 1)
	{
		// We've already seen the "Black Market Available" alert before the market was closed, so just go straight to the main screen
		`HQPRES.UIBlackMarket();
	}
	else
	{
		`HQPRES.UIBlackMarketAlert();
	}

	`GAME.GetGeoscape().Pause();
}

simulated function string GetUIButtonIcon()
{
	return "img:///UILibrary_StrategyImages.X2StrategyMap.MissionIcon_BlackMarket";
}

simulated function string GetUIButtonTooltipTitle()
{
	return Caps(GetDisplayName());
}

simulated function string GetUIButtonTooltipBody()
{
	local string TooltipStr, ScanTimeValue, ScanTimeLabel;
	local int DaysRemaining;

	if (!bIsOpen)
	{
		DaysRemaining = GetNumScanDaysRemaining();
		if (DaysRemaining > 0)
		{
			ScanTimeValue = string(DaysRemaining);
			ScanTimeLabel = class'UIUtilities_Text'.static.GetDaysString(DaysRemaining);
			TooltipStr = ScanTimeValue @ ScanTimeLabel @ m_strRemainingLabel;
		}
	}

	return TooltipStr;
}

//---------------------------------------------------------------------------------------

protected function bool CurrentlyInteracting()
{
	// Notify only if we haven't opened the Black Market yet
	// and the avenger is landed here, then yes, we're interacting.
	return (!bIsOpen && !bForceClosed && GetReference() == class'UIUtilities_Strategy'.static.GetXComHQ().CurrentLocation);
}

//---------------------------------------------------------------------------------------

DefaultProperties
{
	PriceReductionScalar=1.0f
}

error: pathspec 'X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_BlackMarket.uc' did not match any file(s) known to git


Add XCGS_HQProjectPsiTraining.uc for modification (#534)

//---------------------------------------------------------------------------------------
//  FILE:    XComGameState_HeadquartersProjectPsiTraining.uc
//  AUTHOR:  Mark Nauta  --  11/11/2014
//  PURPOSE: This object represents the instance data for an XCom HQ psi training project
//           Will eventually be a component
//
//---------------------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//---------------------------------------------------------------------------------------
class XComGameState_HeadquartersProjectPsiTraining extends XComGameState_HeadquartersProject native(Core);

var int iAbilityRank;	// the rank of the ability the psi operative will learn upon completing the project
var int iAbilityBranch; // the branch of the ability the psi operative will learn upon completing the project

var bool bForcePaused;

//---------------------------------------------------------------------------------------
function SetProjectFocus(StateObjectReference FocusRef, optional XComGameState NewGameState, optional StateObjectReference AuxRef)
{
	local XComGameStateHistory History;
	local XComGameState_Unit UnitState;
	local XComGameState_GameTime TimeState;

	History = `XCOMHISTORY;
	ProjectFocus = FocusRef; // Unit
	AuxilaryReference = AuxRef; // Facility

	UnitState = XComGameState_Unit(NewGameState.GetGameStateForObjectID(ProjectFocus.ObjectID));
	if (UnitState == none)
	{
		UnitState = XComGameState_Unit(History.GetGameStateForObjectID(ProjectFocus.ObjectID));
	}

	// If the soldier is not already a Psi Operative (if they are, the ability will be assigned from the player's choice)
	if (UnitState.GetSoldierClassTemplateName() != 'PsiOperative')
	{
		// Randomly choose a branch and ability from the starting two tiers of the Psi Op tree
		iAbilityRank = `SYNC_RAND(2);
		iAbilityBranch = `SYNC_RAND(2);
		ProjectPointsRemaining = CalculatePointsToTrain(true);
	}
	else
	{
		ProjectPointsRemaining = CalculatePointsToTrain();
	}

	InitialProjectPoints = ProjectPointsRemaining;

	UpdateWorkPerHour(NewGameState);
	TimeState = XComGameState_GameTime(History.GetSingleGameStateObjectForClass(class'XComGameState_GameTime'));
	StartDateTime = TimeState.CurrentTime;

	if (`STRATEGYRULES != none)
	{
		if (class'X2StrategyGameRulesetDataStructures'.static.LessThan(TimeState.CurrentTime, `STRATEGYRULES.GameTime))
		{
			StartDateTime = `STRATEGYRULES.GameTime;
		}
	}

	if(MakingProgress())
	{
		SetProjectedCompletionDateTime(StartDateTime);
	}
	else
	{
		// Set completion time to unreachable future
		CompletionDateTime.m_iYear = 9999;
	}
}

//---------------------------------------------------------------------------------------
function int CalculatePointsToTrain(optional bool bClassTraining = false)
{
	local XComGameStateHistory History;
	local XComGameState_HeadquartersXCom XComHQ;
	local XComGameState_Unit Unit;
	local int RankDifference;

	History = `XCOMHISTORY;
	XComHQ = XComGameState_HeadquartersXCom(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));
	if (bClassTraining)
	{
		return XComHQ.GetPsiTrainingDays() * XComHQ.XComHeadquarters_DefaultPsiTrainingWorkPerHour * 24;
	}
	else
	{
		Unit = XComGameState_Unit(History.GetGameStateForObjectID(ProjectFocus.ObjectID));
		RankDifference = Max(iAbilityRank - Unit.GetRank(), 0);
		return (XComHQ.GetPsiTrainingDays() + Round(XComHQ.GetPsiTrainingScalar() * float(RankDifference))) * XComHQ.XComHeadquarters_DefaultPsiTrainingWorkPerHour * 24;
	}
}

//---------------------------------------------------------------------------------------
function int CalculateWorkPerHour(optional XComGameState StartState = none, optional bool bAssumeActive = false)
{
	local XComGameStateHistory History;
	local XComGameState_HeadquartersXCom XComHQ;
	local int iTotalWork;

	History = `XCOMHISTORY;
	XComHQ = XComGameState_HeadquartersXCom(History.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));
	iTotalWork = XComHQ.PsiTrainingRate;

	// Can't make progress when paused
	if (bForcePaused && !bAssumeActive)
	{
		return 0;
	}

	return iTotalWork;
}

//---------------------------------------------------------------------------------------
function OnProjectCompleted()
{
	local HeadquartersOrderInputContext OrderInput;
	local XComGameState_Unit Unit;
	local X2AbilityTemplate AbilityTemplate;
	local name AbilityName;

	OrderInput.OrderType = eHeadquartersOrderType_PsiTrainingCompleted;
	OrderInput.AcquireObjectReference = self.GetReference();

	class'XComGameStateContext_HeadquartersOrder'.static.IssueHeadquartersOrder(OrderInput);

	Unit = XComGameState_Unit(`XCOMHISTORY.GetGameStateForObjectID(ProjectFocus.ObjectID));
	AbilityName = Unit.GetAbilityName(iAbilityRank, iAbilityBranch);
	AbilityTemplate = class'X2AbilityTemplateManager'.static.GetAbilityTemplateManager().FindAbilityTemplate(AbilityName);

	`HQPRES.UIPsiTrainingComplete(ProjectFocus, AbilityTemplate);

	// Start Issue
	`XEVENTMGR.TriggerEvent('PsiProjectCompleted', self, self);
}

//---------------------------------------------------------------------------------------
DefaultProperties
{
}

error: pathspec 'X2WOTCCommunityHighlander/Src/XComGame/Classes/XComGameState_HeadquartersProjectPsiTraining.uc' did not match any file(s) known to git


quick fix

quick fix

//---------------------------------------------------------------------------------------
//  FILE:    X2SitRepEffect_GrantAbilities.uc
//  AUTHOR:  David Burchanowski  --  11/1/2016
//  PURPOSE: Allows sitreps to give abilities to units
//
//---------------------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//---------------------------------------------------------------------------------------

class X2SitRepEffect_GrantAbilities extends X2SitRepEffectTemplate;

var array<name> AbilityTemplateNames; // Abilities to grant

var array<name> CharacterTemplateNames; // Characters to grant abilities to
var array<ETeam> Teams; //CHL issue #445 allow mods to decide which team(s) receive this ability
var bool GrantToSoldiers; // If true, will grant the specified abilities to all soldier classes

// If you need different/more precise control of which units get which abilities, you can override
// this function with a subclass
function GetAbilitiesToGrant(XComGameState_Unit UnitState, out array<name> AbilityTemplates)
{
	AbilityTemplates.Length = 0;

	if(CharacterTemplateNames.Length == 0 && GrantToSoldiers == false
	|| CharacterTemplateNames.Find(UnitState.GetMyTemplateName()) != INDEX_NONE
	|| Teams.Find(UnitState.GetTeam()) != INDEX_NONE
	|| (GrantToSoldiers && UnitState.IsSoldier()))
	{
		AbilityTemplates = AbilityTemplateNames;
	}

}

//---------------------------------------------------------------------------------------
//  FILE:    X2SitRepEffect_GrantAbilities.uc
//  AUTHOR:  David Burchanowski  --  11/1/2016
//  PURPOSE: Allows sitreps to give abilities to units
//
//---------------------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//---------------------------------------------------------------------------------------

class X2SitRepEffect_GrantAbilities extends X2SitRepEffectTemplate;

var array<name> CharacterTemplateNames; // Characters to grant abilities to
var array<name> AbilityTemplateNames; // Abilities to grant
var array<ETeam> Teams; //CHL issue #445 allow mods to decide which team(s) receive this ability

var bool GrantToSoldiers; // If true, will grant the specified abilities to all soldier classes

// If you need differet/more precise control of which units get which abilities, you can override
// this function with a subclass
function GetAbilitiesToGrant(XComGameState_Unit UnitState, out array<name> AbilityTemplates)
{
	local bool GrantToAllUnits;

	AbilityTemplates.Length = 0;

	GrantToAllUnits = CharacterTemplateNames.Length == 0 && GrantToSoldiers == false;
	if( GrantToAllUnits
		|| CharacterTemplateNames.Find(UnitState.GetMyTemplateName()) != INDEX_NONE
		|| (GrantToSoldiers && UnitState.IsSoldier()))
	{
		AbilityTemplates = AbilityTemplateNames;
	}
}


Update filehandler.uc

Update filehandler.uc

Added pattern for Print #{filenum} not followed by anything else

# filehandler.uc - uCalc Transformation file
# This file was saved with uCalc Transform 2.95 on 3/14/2014 8:52:21 AM
# Comment: File handler

ExternalKeywords: Exclude, Comment, Selected, ParentChild, FindMode, InputFile, OutputFile, BatchAction, SEND
ExternalKeywords: Highlight, ForeColor, BackColor, FontName, FontSize, FontStyle
ExternalKeywords: FilterEndText, FilterSeparator, FilterSort, FilterSortFunc, FilterStartText, FilterUnique, FilterTally

FindMode: Replace

# Definitions

# Search Criteria

Criteria: 0
Enabled: True
Exclude: False
Comment: File handler
Selected: False
Highlight: True
ForeColor: ControlText
BackColor: Aqua
FontName:
FontSize:
FontStyle:
CaseSensitive: False
QuoteSensitive: True
CodeBlockSensitive: True
FilterEndText:
FilterSeparator: {#10}
FilterSort: False
FilterSortFunc:
FilterStartText:
FilterUnique: False
FilterTally: False
Min: 0
Max: -1
MinSoft: 0
MaxSoft: -1
BatchAction: Transform
InputFile:
OutputFile:
SEND:
StartAfter: 0
StopAfter: -1
SkipOver: False
ParentChild: 0
Pass: 0
PassOnce: True
Precedence: 0
RightToLeft: False

Criteria: 1
Comment:
Pass: 1

Criteria: 2
BackColor: Yellow
SkipOver: True
Find: ' {Comment:".*"}
Replace: [Skip over]

Criteria: 3
BackColor: DeepSkyBlue
Find: {@Start}
Replace: #include <iostream>
         #include <fstream>
         {@Var: FreeFileNum}

Criteria: 4
BackColor: DeepSkyBlue
Find: Open {filespec}
      { For {{Input: Input}|{Output: Output}|{Append: Append}|{Binary: Binary}|{Random: Random}}|{Default: } }
      { Access Read | Access Write | Access Read Write | }
      { Lock {{LockRead: Read}|{LockWrite: Write}|{LockBoth: Read Write}|{LockShared: Shared}}|{LockDefault: } }
      As [#]{filenum} [Len = {size=128}]
Replace: fstream file_{filenum} (string({filespec}).c_str(),
            {Input:   ios::in}
            {Output:  ios::out | ios::trunc}
            {Append:  ios::out | ios::app}
            {Binary:  ios::binary | ios::in | ios::out}
            {Random:  ios::binary | ios::in | ios::out}
            {Default: ios::binary | ios::in | ios::out}
         );

Criteria: 5
BackColor: Lime
Find: Close [#]{filenum}
Replace: file_{filenum}.close() ' PB: Close #{filenum}

Criteria: 6
BackColor: RoyalBlue
PassOnce: False
Find: Close [#]{file1}, {more}
Replace: Close {file1}
         Close {more}

Criteria: 7
BackColor: Pink
Find: Seek [#] {filenum}, {position}
Replace: file_{filenum}.seekg({position}-1)
         file_{filenum}.seekp({position}-1)

Criteria: 8
Find: Seek([#] {filenum})
Replace: file_{filenum}.tellg()+1

Criteria: 9
BackColor: SlateBlue
Find: LOF({filenum})
Replace: (missing)

Criteria: 10
Find: EOF({filenum})
Replace: file_{filenum}.eof()

Criteria: 11
Find: FreeFile
Replace: {@Eval: FreeFileNum += 1; FreeFileNum}

Criteria: 12
BackColor: Green
Find: Get$ [#] {filenum}, {count}, {StringVar}
Replace: {StringVar}.resize({count})
         file_{filenum}.read(&{StringVar}[0], {count})

Criteria: 13
BackColor: SandyBrown
Find: Put$ [#] {filenum}, {text}
Replace: file_{filenum}.write(&{text}[0], {text}.size())

Criteria: 14
Find: IsFile({file})
Replace: PB_ISFILE({file})

Criteria: 15
BackColor: Gold
Find: EXE.Extn$
Replace: PB_EXE_EXTN

Criteria: 16
BackColor: Silver
Find: EXE.Full$
Replace: PB_EXE_FULL()

Criteria: 17
Find: EXE.Name$
Replace: PB_EXE_NAME

Criteria: 18
BackColor: CornflowerBlue
Find: EXE.Namex$
Replace: PB_EXE_NAMEX

Criteria: 19
Find: EXE.Path$
Replace: PB_EXE_PATH

Criteria: 20
Find: Dir$({mask})
Replace: PB_DIR({mask})

Criteria: 21
Find: Dir$([Next])
Replace: PB_DIR_NEXT()

Criteria: 22
Selected: True
Find: Print #{filenum}
Replace: file_{filenum} << endl

Criteria: 23
Find: Print #{filenum}, {text}
Replace: file_{filenum} << {text} << endl

Criteria: 24
Find: Print #{filenum}, {text};
Replace: file_{filenum} << {text}

Criteria: 25
PassOnce: False
Find: Print #{filenum}, {text}; {MoreText}
Replace: Print #{filenum}, {text} << {MoreText}

Criteria: 26
Comment:
Pass: 2

Criteria: 27
BackColor: Yellow
Find: fstream {file} ({args+})
Replace: {@Eval: Replace('{Self}', '{"[ \n]+"}', ' ')}

# End Search

# filehandler.uc - uCalc Transformation file
# This file was saved with uCalc Transform 2.95 on 3/13/2014 3:53:07 PM
# Comment: File handler

ExternalKeywords: Exclude, Comment, Selected, ParentChild, FindMode, InputFile, OutputFile, BatchAction, SEND
ExternalKeywords: Highlight, ForeColor, BackColor, FontName, FontSize, FontStyle
ExternalKeywords: FilterEndText, FilterSeparator, FilterSort, FilterSortFunc, FilterStartText, FilterUnique, FilterTally

FindMode: Replace

# Definitions

# Search Criteria

Criteria: 0
Enabled: True
Exclude: False
Comment: File handler
Selected: False
Highlight: True
ForeColor: ControlText
BackColor: Aqua
FontName:
FontSize:
FontStyle:
CaseSensitive: False
QuoteSensitive: True
CodeBlockSensitive: True
FilterEndText:
FilterSeparator: {#10}
FilterSort: False
FilterSortFunc:
FilterStartText:
FilterUnique: False
FilterTally: False
Min: 0
Max: -1
MinSoft: 0
MaxSoft: -1
BatchAction: Transform
InputFile:
OutputFile:
SEND:
StartAfter: 0
StopAfter: -1
SkipOver: False
ParentChild: 0
Pass: 0
PassOnce: True
Precedence: 0
RightToLeft: False

Criteria: 1
Comment:
Pass: 1

Criteria: 2
BackColor: Yellow
SkipOver: True
Find: ' {Comment:".*"}
Replace: [Skip over]

Criteria: 3
BackColor: DeepSkyBlue
Find: {@Start}
Replace: #include <iostream>
         #include <fstream>
         {@Var: FreeFileNum}

Criteria: 4
BackColor: DeepSkyBlue
Find: Open {filespec}
      { For {{Input: Input}|{Output: Output}|{Append: Append}|{Binary: Binary}|{Random: Random}}|{Default: } }
      { Access Read | Access Write | Access Read Write | }
      { Lock {{LockRead: Read}|{LockWrite: Write}|{LockBoth: Read Write}|{LockShared: Shared}}|{LockDefault: } }
      As [#]{filenum} [Len = {size=128}]
Replace: fstream file_{filenum} (string({filespec}).c_str(),
            {Input:   ios::in}
            {Output:  ios::out | ios::trunc}
            {Append:  ios::out | ios::app}
            {Binary:  ios::binary | ios::in | ios::out}
            {Random:  ios::binary | ios::in | ios::out}
            {Default: ios::binary | ios::in | ios::out}
         );

Criteria: 5
BackColor: Lime
Find: Close [#]{filenum}
Replace: file_{filenum}.close() ' PB: Close #{filenum}

Criteria: 6
BackColor: RoyalBlue
PassOnce: False
Find: Close [#]{file1}, {more}
Replace: Close {file1}
         Close {more}

Criteria: 7
BackColor: Pink
Find: Seek [#] {filenum}, {position}
Replace: file_{filenum}.seekg({position}-1)
         file_{filenum}.seekp({position}-1)

Criteria: 8
Find: Seek([#] {filenum})
Replace: file_{filenum}.tellg()+1

Criteria: 9
BackColor: SlateBlue
Find: LOF({filenum})
Replace: (missing)

Criteria: 10
Find: EOF({filenum})
Replace: file_{filenum}.eof()

Criteria: 11
Find: FreeFile
Replace: {@Eval: FreeFileNum += 1; FreeFileNum}

Criteria: 12
BackColor: Green
Find: Get$ [#] {filenum}, {count}, {StringVar}
Replace: {StringVar}.resize({count})
         file_{filenum}.read(&{StringVar}[0], {count})

Criteria: 13
BackColor: SandyBrown
Find: Put$ [#] {filenum}, {text}
Replace: file_{filenum}.write(&{text}[0], {text}.size())

Criteria: 14
Find: IsFile({file})
Replace: PB_ISFILE({file})

Criteria: 15
BackColor: Gold
Find: EXE.Extn$
Replace: PB_EXE_EXTN

Criteria: 16
BackColor: Silver
Find: EXE.Full$
Replace: PB_EXE_FULL()

Criteria: 17
Find: EXE.Name$
Replace: PB_EXE_NAME

Criteria: 18
BackColor: CornflowerBlue
Find: EXE.Namex$
Replace: PB_EXE_NAMEX

Criteria: 19
Find: EXE.Path$
Replace: PB_EXE_PATH

Criteria: 20
Find: Dir$({mask})
Replace: PB_DIR({mask})

Criteria: 21
Find: Dir$([Next])
Replace: PB_DIR_NEXT()

Criteria: 22
Find: Print #{filenum}, {text}
Replace: file_{filenum} << {text} << endl

Criteria: 23
Find: Print #{filenum}, {text};
Replace: file_{filenum} << {text}

Criteria: 24
Selected: True
PassOnce: False
Find: Print #{filenum}, {text}; {MoreText}
Replace: Print #{filenum}, {text} << {MoreText}

Criteria: 25
Comment:
Pass: 2

Criteria: 26
BackColor: Yellow
Find: fstream {file} ({args+})
Replace: {@Eval: Replace('{Self}', '{"[ \n]+"}', ' ')}

# End Search


Update implicit-dim.uc

Update implicit-dim.uc

Added code to comment out explicit declarations of Windows API routines
Added code to ensure consistent casing (upper/lower case) for names

# implicit-dim.uc - uCalc Transformation file
# This file was saved with uCalc Transform 2.96 on 5/12/2014 10:33:51 AM
# Comment: Declares variables (with Dim) that were not explicitely declared before

ExternalKeywords: Exclude, Comment, Selected, ParentChild, FindMode, InputFile, OutputFile, BatchAction, SEND
ExternalKeywords: Highlight, ForeColor, BackColor, FontName, FontSize, FontStyle
ExternalKeywords: FilterEndText, FilterSeparator, FilterSort, FilterSortFunc, FilterStartText, FilterUnique, FilterTally

FindMode: Replace

# Definitions

# Search Criteria

Criteria: 0
Enabled: True
Exclude: False
Comment: Declares variables (with Dim) that were not explicitely declared before
Selected: False
Highlight: False
ForeColor: ControlText
BackColor: Aqua
FontName:
FontSize:
FontStyle:
CaseSensitive: False
QuoteSensitive: True
CodeBlockSensitive: True
FilterEndText:
FilterSeparator: {#10}
FilterSort: False
FilterSortFunc:
FilterStartText:
FilterUnique: False
FilterTally: False
Min: 0
Max: -1
MinSoft: 0
MaxSoft: -1
BatchAction: Transform
InputFile: ImplicitDim.Bas
OutputFile:
SEND:
StartAfter: 0
StopAfter: -1
SkipOver: False
ParentChild: 0
Pass: 0
PassOnce: True
Precedence: 0
RightToLeft: False

Criteria: 1
Find: {@Note:
         In addition to declaring variables that were not previously declared
         explicitely, this transform also comments out user declarations that
         are from the Windows API, since Windows.h already takes care of it,
         and the PB mixed casing of an API equate might not correspond with
         the exact API case-sensitive C++ orthograph.
      }

Replace: {@Define::
            Token: \x27.* ~~ Properties: ucWhitespace
            Token: _[^\n]*\n ~~ Properties: ucWhitespace
         }
         {@Define:
            Var: Globals As Table
            Var: ImplicitDim As Table
            Var: ExplicitDim As Table
            Var: CurrentRoutine As String
            Var: ExpIndex As Long
            Var: ImpIndex As Long
            Var: GlobalIndex As Long
         }
         {@Exec:
            Split(File("WinAPIKeywords.txt"))
            uc_For(x, 1, StringItemCount, 2, Insert(Globals, StringItem(x)))
         }

Criteria: 2
Comment: Teporarily adds Dim keyword in front of args for further parsing
Pass: 1

Criteria: 3
Find: {nl}{routine: Sub | Function } {etc}({args})
Replace: {nl}{routine} {etc}(Dim {args})

Criteria: 4
SkipOver: True
Find: {nl}Function =
Replace: [Skip over]

Criteria: 5
Comment: Inserts explicitly Dimmed variable names in global or local tables
Pass: 2

Criteria: 6
Find: Global{" +"}{variable:"[a-z][a-z0-9_]*[#!?%&]*"}
Replace: {Self}{@Eval: Insert(Globals, "{variable}")}

Criteria: 7
BackColor: Silver
Find: {nl}{ Macro | Type | Union | % | $[$] | Declare {func:1} }  {name:1}
Replace: {Self}{@Eval: Insert(Globals, "{name}")}

Criteria: 8
BackColor: Lime
Find: {nl}{ Sub | Function }{" +"}{RoutineName:"[a-z0-9_]+"}
Replace: {Self}{@Define:
            Var: {RoutineName}ExplicitDim As Table
            Var: {RoutineName}ImplicitDim As Table
         }{@Eval: SetVar(CurrentRoutine, "{RoutineName}"); Insert(Globals,"{RoutineName}")}

Criteria: 9
Find: {nl}End { Sub | Function }
Replace: {Self}{@Eval: SetVar(CurrentRoutine, "")}

Criteria: 10
BackColor: Pink
Find: {declare: Dim [[Optional] { ByVal | ByRef }] | Local | Static | Register | fstream }
      {" +"}{variable:"[a-z][a-z0-9_]*[#!?%&]*"}
Replace: {Self}{@Eval: Insert(~Eval(CurrentRoutine)ExplicitDim, "{variable}")}

Criteria: 11
Comment: Temporarily inserts declaration for each individual variable a lines with a list of multiple vars, for easier parsing
BackColor: SlateBlue
PassOnce: False
Find: {declare: Global|Dim|Local|Static|Register} {variable},
Replace: {declare} {variable} ::: {declare}

Criteria: 12
Selected: True
Find: {nl}%{equate:1} = {@If: Index(Globals, {equate})}
Replace: {nl} ' <WinAPI> {equate} =

Criteria: 13
Find: {nl}Declare {method: Sub | Function } {name:1}  {@If: Index(Globals, {name})}
Replace: {nl} ' <WinAPI> Declare {method} {name}

Criteria: 14
Comment: Places non-Dimmed variable names in separate local tables
Pass: 3

Criteria: 15
Find: [{eq: %}]{name:"[a-z][a-z0-9_]*[#!?%&]*"} [{IsFunc:" *\("}]
Replace: {eq}{@Eval:
            ExpIndex    = Index(~Eval(CurrentRoutine)ExplicitDim, "{name}")
            ImpIndex    = Index(~Eval(CurrentRoutine)ImplicitDim, "{name}")
            GlobalIndex = Index(Globals, "{name}")
            IIf(ExpIndex+ImpIndex+GlobalIndex == 0 And "{IsFunc}" == "",
                Insert(~Eval(CurrentRoutine)ImplicitDim, "{name}"))

            text = "{name}"
            IIf(GlobalIndex, text = ReadKey(Globals, GlobalIndex))
            IIf(ExpIndex, text = ReadKey(~Eval(CurrentRoutine)ExplicitDim, ExpIndex))
            IIf(ImpIndex, text = ReadKey(~Eval(CurrentRoutine)ImplicitDim, ImpIndex))
            text + "{IsFunc}"
         }

Criteria: 16
SkipOver: True
Find: {"[a-z0-9_]+"}  {UDT:"\.[a-z0-9_\@\.]+"}
Replace: [Skip over]

Criteria: 17
SkipOver: True
Find: {"&h[0-9a-f]+"}
Replace: [Skip over]

Criteria: 18
SkipOver: True
Find: {@Eval: "{'"+Retain(FileText("PBKeywords.txt"), "{keyword:'.*'}", Delim("\b|"))+"\b'}"}
Replace: [Skip over]

Criteria: 19
BackColor: Brown
Find: {"\n"}{ Sub | Function }{" +"}{RoutineName:"[a-z0-9_]+"}
Replace: {Self}{@Eval: SetVar(CurrentRoutine, "{RoutineName}")}

Criteria: 20
Find: {"\n"}End { Sub | Function }
Replace: {Self}{@Eval: SetVar(CurrentRoutine, "")}

Criteria: 21
Comment: Inserts local Dim statements for variables that were not dimmed
Pass: 4

Criteria: 22
BackColor: Purple
Find: {nl}{ Sub | Function }{" +"}{RoutineName:"[a-z0-9_]+"} {etc}
Replace: {Self}
         {@Eval:
            Range(1, Count({RoutineName}ImplicitDim),
            {Q}"   Dim "+ReadKey({RoutineName}ImplicitDim, x)+" ' Implicit"+Chr(10){Q})
         }

Criteria: 23
Comment: Clean up (temp declaration statements removed)
Pass: 5

Criteria: 24
BackColor: Violet
Find: ::: {declare:1}
Replace: ,

Criteria: 25
BackColor: CornflowerBlue
Find: (Dim {args})
Replace: ({@Eval: Replace("{args}", "::: Dim", ",")})

Criteria: 26
Find: Dim {nl}
Replace: {Nothing}

# End Search

# implicit-dim.uc - uCalc Transformation file
# This file was saved with uCalc Transform 2.96 on 5/9/2014 10:15:18 AM
# Comment: Declares variables (with Dim) that were not explicitely declared before

ExternalKeywords: Exclude, Comment, Selected, ParentChild, FindMode, InputFile, OutputFile, BatchAction, SEND
ExternalKeywords: Highlight, ForeColor, BackColor, FontName, FontSize, FontStyle
ExternalKeywords: FilterEndText, FilterSeparator, FilterSort, FilterSortFunc, FilterStartText, FilterUnique, FilterTally

FindMode: Replace

# Definitions

# Search Criteria

Criteria: 0
Enabled: True
Exclude: False
Comment: Declares variables (with Dim) that were not explicitely declared before
Selected: False
Highlight: False
ForeColor: ControlText
BackColor: Aqua
FontName:
FontSize:
FontStyle:
CaseSensitive: False
QuoteSensitive: True
CodeBlockSensitive: True
FilterEndText:
FilterSeparator: {#10}
FilterSort: False
FilterSortFunc:
FilterStartText:
FilterUnique: False
FilterTally: False
Min: 0
Max: -1
MinSoft: 0
MaxSoft: -1
BatchAction: Transform
InputFile: ImplicitDim.Bas
OutputFile:
SEND:
StartAfter: 0
StopAfter: -1
SkipOver: False
ParentChild: 0
Pass: 0
PassOnce: True
Precedence: 0
RightToLeft: False

Criteria: 1
Find:
Replace: {@Define::
            Token: \x27.* ~~ Properties: ucWhitespace
            Token: _[^\n]*\n ~~ Properties: ucWhitespace
         }
         {@Define:
            Var: Globals As Table
            Var: ImplicitDim As Table
            Var: ExplicitDim As Table
            Var: CurrentRoutine As String
            Var: ExpIndex As Long
            Var: ImpIndex As Long
            Var: GlobalIndex As Long
         }

Criteria: 2
Comment: Teporarily adds Dim keyword in front of args for further parsing
Pass: 1

Criteria: 3
Find: {nl}{routine: Sub | Function } {etc}({args})
Replace: {nl}{routine} {etc}(Dim {args})

Criteria: 4
SkipOver: True
Find: {nl}Function =
Replace: [Skip over]

Criteria: 5
Comment: Inserts explicitly Dimmed variable names in global or local tables
Pass: 2

Criteria: 6
Find: Global{" +"}{variable:"[a-z][a-z0-9_]*[#!?%&]*"}
Replace: {Self}{@Eval: Insert(Globals, "{variable}")}

Criteria: 7
BackColor: Silver
Find: {nl}{ Macro | Type | Union | % | $[$] | Declare {func:1} }  {name:1}
Replace: {Self}{@Eval: Insert(Globals, "{name}")}

Criteria: 8
BackColor: Lime
Find: {nl}{ Sub | Function }{" +"}{RoutineName:"[a-z0-9_]+"}
Replace: {Self}{@Define:
            Var: {RoutineName}ExplicitDim As Table
            Var: {RoutineName}ImplicitDim As Table
         }{@Eval: SetVar(CurrentRoutine, "{RoutineName}"); Insert(Globals,"{RoutineName}")}

Criteria: 9
Find: {nl}End { Sub | Function }
Replace: {Self}{@Eval: SetVar(CurrentRoutine, "")}

Criteria: 10
BackColor: Pink
Find: {declare: Dim [[Optional] { ByVal | ByRef }] | Local | Static | Register | fstream }
      {" +"}{variable:"[a-z][a-z0-9_]*[#!?%&]*"}
Replace: {Self}{@Eval: Insert(~Eval(CurrentRoutine)ExplicitDim, "{variable}")}

Criteria: 11
Comment: Temporarily inserts declaration for each individual variable a lines with a list of multiple vars, for easier parsing
BackColor: SlateBlue
PassOnce: False
Find: {declare: Global|Dim|Local|Static|Register} {variable},
Replace: {declare} {variable} ::: {declare}

Criteria: 12
Comment: Places non-Dimmed variable names in separate local tables
Pass: 3

Criteria: 13
Selected: True
Find: {variable:"[a-z][a-z0-9_]*[#!?%&]*"}
      [{IsFunc:" *\("}]
Replace: {@Eval:
            ExpIndex    = Index(~Eval(CurrentRoutine)ExplicitDim, "{variable}")
            ImpIndex    = Index(~Eval(CurrentRoutine)ImplicitDim, "{variable}")
            GlobalIndex = Index(Globals, "{variable}")
            IIf(ExpIndex+ImpIndex+GlobalIndex == 0 And "{IsFunc}" == "",
                Insert(~Eval(CurrentRoutine)ImplicitDim, "{variable}"))

            text = "{variable}"
            IIf(GlobalIndex, text = ReadKey(Globals, GlobalIndex))
            IIf(ExpIndex, text = ReadKey(~Eval(CurrentRoutine)ExplicitDim, ExpIndex))
            IIf(ImpIndex, text = ReadKey(~Eval(CurrentRoutine)ImplicitDim, ImpIndex))
            text + "{IsFunc}"
         }

Criteria: 14
SkipOver: True
Find: {"[a-z0-9_]+"}  {UDT:"\.[a-z0-9_\@\.]+"}
Replace: [Skip over]

Criteria: 15
SkipOver: True
Find: {"&h[0-9a-f]+"}
Replace: [Skip over]

Criteria: 16
SkipOver: True
Find: {@Eval: "{'"+Retain(FileText("PBKeywords.txt"), "{keyword:'.*'}", Delim("\b|"))+"\b'}"}
Replace: [Skip over]

Criteria: 17
BackColor: Brown
Find: {"\n"}{ Sub | Function }{" +"}{RoutineName:"[a-z0-9_]+"}
Replace: {Self}{@Eval: SetVar(CurrentRoutine, "{RoutineName}")}

Criteria: 18
Find: {"\n"}End { Sub | Function }
Replace: {Self}{@Eval: SetVar(CurrentRoutine, "")}

Criteria: 19
Comment: Inserts local Dim statements for variables that were not dimmed
Pass: 4

Criteria: 20
BackColor: Purple
Find: {nl}{ Sub | Function }{" +"}{RoutineName:"[a-z0-9_]+"} {etc}
Replace: {Self}
         {@Eval:
            Range(1, Count({RoutineName}ImplicitDim),
            {Q}"   Dim "+ReadKey({RoutineName}ImplicitDim, x)+" ' Implicit"+Chr(10){Q})
         }

Criteria: 21
Comment: Clean up (temp declaration statements removed)
Pass: 5

Criteria: 22
BackColor: Violet
Find: ::: {declare:1}
Replace: ,

Criteria: 23
BackColor: CornflowerBlue
Find: (Dim {args})
Replace: ({@Eval: Replace("{args}", "::: Dim", ",")})

Criteria: 24
Find: Dim {nl}
Replace: {Nothing}

# End Search